vue2.x数组劫持原理的实现

所属分类: 网络编程 / JavaScript 阅读数: 586
收藏 0 赞 0 分享

接上篇Vue2.x 对象劫持,继续来写数组劫持

实现原理:
1 重新定义原生数组方法push unshift shift pop splice sort reverse 因为这些方法可以修改原数组。
2 拿到原生数组方法 Object.create(Array.prototype)
3 AOP拦截,再执行重写数组方法前,先执行原生数组方法

核心监听Observer代码

// 把data中的数据 都使用Object.defineProperty重新定义 es5
// Object.defineProperty 不能兼容ie8 及以下 vue2 无法兼容ie8版本
import {arrayMethods} from './array.js'
import {
  isObject,def
} from '../util/index'
// 后续我可以知道它是不是一个已经观察了的数据 __ob__
class Observer{
  constructor(value){ // 仅仅是初始化的操作
    // vue如果数据的层次过多 需要递归的去解析对象中的属性,依次增加set和get方法
    // value.__ob__ = this; // 我给每一个监控过的对象都增加一个__ob__属性
    def(value,'__ob__',this);
    if(Array.isArray(value)){
      // 如果是数组的话并不会对索引进行观测 因为会导致性能问题
      // 前端开发中很少很少 去操作索引 push shift unshift 
      value.__proto__ = arrayMethods;
      // 如果数组里放的是对象我再监控
      this.observerArray(value);
    }else{
       // 对数组监控
      this.walk(value); // 对对象进行观测
    }
  }
  observerArray(value){ // [{}]
    for(let i = 0; i < value.length;i++){
      observe(value[i]);
    }
  }
  walk(data){
    let keys = Object.keys(data); // [name,age,address]
    // 如果这个data 不可配置 直接reurn
    keys.forEach((key)=>{
      defineReactive(data,key,data[key]);
    });
  }
}
function defineReactive(data,key,value){

  observe(value); // 递归实现深度检测
  Object.defineProperty(data,key,{
    configurable:true,
    enumerable:false,
    get(){ // 获取值的时候做一些操作
      return value;
    },
    set(newValue){ // 也可以做一些操作
      console.log('更新数据')
      if(newValue === value) return;
      observe(newValue); // 继续劫持用户设置的值,因为有可能用户设置的值是一个对象
      value = newValue;
    }
  });
}

export function observe(data) {
  let isObj = isObject(data);
  if (!isObj) {
    return
  }
  return new Observer(data); // 用来观测数据
}

重写原生数组方法

// 我要重写数组的那些方法 7个 push shift unshift pop reverse sort splice 会导致数组本身发生变化
// slice()


let oldArrayMethods = Array.prototype;
// value.__proto__ = arrayMethods 原型链查找的问题, 会向上查找,先查找我重写的,重写的没有会继续向上查找
// arrayMethods.__proto__ = oldArrayMethods
export const arrayMethods = Object.create(oldArrayMethods); 

const methods = [
  'push',
  'shift',
  'unshift',
  'pop',
  'sort',
  'splice',
  'reverse'
]
methods.forEach(method=>{
  arrayMethods[method] = function (...args) { 
    const result = oldArrayMethods[method].apply(this,args); // 调用原生的数组方法
    // push unshift 添加的元素可能还是一个对象
    let inserted; // 当前用户插入的元素
    let ob = this.__ob__;
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args;
        break;
      case 'splice': // 3个 新增的属性 splice 有删除 新增的的功能 arr.splice(0,1,{name:1})
        inserted = args.slice(2)
      default:
        break;
    }
    if(inserted) ob.observerArray(inserted); // 将新增属性继续观测


    return result;
  }
})

工具方法定义如下:

/**
 * 
 * @param {*} data 当前数据是不是对象
 */
export function isObject(data) {
  return typeof data === 'object' && data !== null;
}
export function def(data,key,value){
  Object.defineProperty(data,key,{
    enumerable:false,
    configurable:false,
    value
  })
}

更多精彩内容其他人还在看

详解javascript 变量提升(Hoisting)

这篇文章主要介绍了详解javascript 变量提升(Hoisting),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

javascript中数组的常用算法深入分析

这篇文章主要给大家介绍了关于javascript中数组的常用算法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用javascript具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
收藏 0 赞 0 分享

详解微信小程序框架wepy踩坑记录(与vue对比)

这篇文章主要介绍了详解微信小程序框架wepy踩坑记录(与vue对比),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

详解用Webpack与Babel配置ES6开发环境

这篇文章主要介绍了详解用Webpack与Babel配置ES6开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

如何使用pm2快速将项目部署到远程服务器

这篇文章主要介绍了如何使用pm2快速将项目部署到远程服务器,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

Jquery的autocomplete插件用法及参数讲解

今天小编就为大家分享一篇关于Jquery的autocomplete插件用法及参数讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
收藏 0 赞 0 分享

通过JS运行机制的角度说说作用域

这篇文章主要给大家介绍了如何通过JS运行机制的角度说说作用域的相关资料,文中通过图文介绍的非常详细,对大家的学习或者使用JS作用域具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
收藏 0 赞 0 分享

Vue项目引发的「过滤器」使用教程

这篇文章主要给大家介绍了关于Vue项目引发的「过滤器」使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用vue具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
收藏 0 赞 0 分享

利用Vconsole和Fillder进行移动端抓包调试方法

这篇文章主要介绍了利用Vconsole和Fillder进行移动端抓包调试,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

移动端(微信等使用vConsole调试console的方法

这篇文章主要介绍了移动端(微信等使用vConsole调试console的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享
查看更多