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

所属分类: 网络编程 / JavaScript 阅读数: 297
收藏 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
  })
}

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

jQuery中图片展示插件highslide.js的简单dom

前言 今天用用了一款图片展示插件highslide.js,感觉用起来很是舒畅,几乎不用怎么写代码,只需要知道如何写参数就行了。 那么这么牛叉的插件我们该如何用哪,下面我就跟大家讲解一下。 一、引入 首先我们运用绝对路径引入,这一般都是在实际项目中引用的方法,我们下载时候会... 查看详情
收藏 0 赞 0 分享

基于vue-ssr的静态网站生成器VuePress 初体验

什么是VuePress VuePress由两部分组成:一个基于Vue的轻量级静态网站生成器,以及为编写技术文档而优化的默认主题。 它是为了满足Vue自己的子项目文档的需求而创建的。 VuePress为每一个由它生成的页面提供预加载的html,不仅加载速度极佳,同时对s... 查看详情
收藏 0 赞 0 分享

Angular数据绑定机制原理

1.Angular.js扩展浏览器的事件循环 浏览器持续等待例如用户交互这样的事件。当你在一个<input>标签里输入字符之后,这个事件的回调函数在JS解释器中执行了其包含的DOM操作,执行完毕后,浏览器响应地对DOM做出了变化。Angular拓展了这个事件循环,使... 查看详情
收藏 0 赞 0 分享

微信小程序如何像vue一样在动态绑定类名

小程序 开发中遇到这样一个问题... 排行榜开发的时候,前三名的样式不同,其余的样式一样。但是都是通过同一元素来遍历的,当时卡了一下。后来发现有module模块化这一概念,于是查了下api,一下子就做出来了。   就是不同名次上边的样式根据实际情况展示效果。 模... 查看详情
收藏 0 赞 0 分享

Vue进度条progressbar组件功能

效果图 首先我们看一下进度条组件运行出来的效果,如下图显示 进度条组件 实现过程 ◾ 项目搭建 progressbar组件在一个可以直接运行的npm包,通过Yeoman进行构建,再通过Gulp+Webpack构建工具,生成的工作目录如下,其中各个文件夹的... 查看详情
收藏 0 赞 0 分享

redux中间件之redux-thunk的具体使用

redux的核心概念其实很简单:将需要修改的state都存入到store里,发起一个action用来描述发生了什么,用reducers描述action如何改变state tree 。创建store的时候需要传入reducer,真正能改变store中数据的是store.dispat... 查看详情
收藏 0 赞 0 分享

JS实现二维数组横纵列转置的方法

我想将一个二维数组横纵列转过来,我就不信只有我有这个需求,可是百度了好久,四海八荒都找遍了…… 后来证明还是大神说的google好用 ~ 第一条就是,鄙视臭百度 此番记录下来,也方便各位道友查阅(好想说“仙友”,最近被一部剧毒害的后遗症 ~~~) var n... 查看详情
收藏 0 赞 0 分享

关于Angularjs中跨域设置白名单问题

在config中注入$sceDelegateProvider服务使用resourceUrlWhitelist([])方法添加白名单      跨域时将method的属性设置为"jsonp"就可以访问了 app.config(["... 查看详情
收藏 0 赞 0 分享

浅析vue中常见循环遍历指令的使用 v-for

vue中循环遍历使用的指令是v-for 1.v-for遍历数组 (1)value in arr 遍历数组中的元素 (2)(value,index) in arr 遍历数组中的元素和数组下标 运行代码: <body> <div class=... 查看详情
收藏 0 赞 0 分享

vue双向数据绑定知识点总结

1.原理 vue的双向数据绑定的原理相信大家都十分了解;主要是通过ES5的Object对象的defineProperty属性;重写data的set和get函数来实现的 所以接下来不使用ES6进行实际的代码开发;过程中如果函数使用父级this的情况;还是使用显示缓存中间变量... 查看详情
收藏 0 赞 0 分享
查看更多