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


Posted in Javascript onApril 19, 2020

接上篇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
  })
}

到此这篇关于vue2.x数组劫持原理的实现的文章就介绍到这了,更多相关vue2.x 数组劫持内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
css transform 3D幻灯片特效实现步骤解读
Mar 27 Javascript
验证控件与Button的OnClientClick事件详细解析
Dec 04 Javascript
javascript获得当前的信息的一些常用命令
Feb 25 Javascript
js console.log打印对像与数组用法详解
Jan 21 Javascript
简述JavaScript提交表单的方式 (Using JavaScript Submit Form)
Mar 18 Javascript
再次谈论React.js实现原生js拖拽效果引起的一系列问题
Apr 03 Javascript
最全面的JS倒计时代码
Sep 17 Javascript
KnockoutJS 3.X API 第四章之事件event绑定
Oct 10 Javascript
JS实现加载时锁定HTML页面元素的方法
Jun 24 Javascript
react实现菜单权限控制的方法
Dec 11 Javascript
微信小程序实现自定义picker选择器弹窗内容
May 26 Javascript
Javascript ParentNode和ChildNode接口原理解析
Mar 16 Javascript
vue2.x 对象劫持的原理实现
Apr 19 #Javascript
基于js判断浏览器是否支持webGL
Apr 18 #Javascript
JavaScript对象字面量和构造函数原理与用法详解
Apr 18 #Javascript
javascript 内存模型实例详解
Apr 18 #Javascript
javascript-hashchange事件和历史状态管理实例分析
Apr 18 #Javascript
javascript使用Blob对象实现的下载文件操作示例
Apr 18 #Javascript
原生js实现的观察者和订阅者模式简单示例
Apr 18 #Javascript
You might like
phpmyadmin下载、安装、配置教程
2017/05/16 PHP
php图片裁剪函数
2018/10/31 PHP
Laravel框架路由管理简单示例
2019/05/07 PHP
laravel 中某一字段自增、自减的例子
2019/10/11 PHP
项目实践之javascript技巧
2007/12/06 Javascript
jquery form表单提交插件asp.net后台中文解码
2010/06/12 Javascript
js 纯数字不重复排列的另类方法
2010/07/17 Javascript
使用js的replace()方法查找字符示例代码
2013/10/28 Javascript
使用Object.defineProperty实现简单的js双向绑定
2016/04/15 Javascript
浅析jquery unbind()方法移除元素绑定的事件
2016/05/24 Javascript
微信小程序 wx.uploadFile无法上传解决办法
2016/12/14 Javascript
利用jQuery实现滑动开关按钮效果(附demo源码下载)
2017/02/07 Javascript
JavaScript创建对象的七种方式(推荐)
2017/06/26 Javascript
bootstrap fileinput实现文件上传功能
2017/08/23 Javascript
JS关于刷新页面的相关总结
2018/05/09 Javascript
微信小程序页面间传递数组对象方法解析
2019/11/06 Javascript
Python实现比较两个列表(list)范围
2015/06/12 Python
Python的条件语句与运算符优先级详解
2015/10/13 Python
Python基于tkinter模块实现的改名小工具示例
2017/07/27 Python
Python学习笔记之字符串和字符串方法实例详解
2019/08/22 Python
在python Numpy中求向量和矩阵的范数实例
2019/08/26 Python
如何解决django-celery启动后迅速关闭
2019/10/16 Python
Keras 快速解决OOM超内存的问题
2020/06/11 Python
查看keras的默认backend实现方式
2020/06/19 Python
英国知名小木屋定制网站:Tiger Sheds
2020/03/06 全球购物
PHP中如何创建和修改数组
2012/05/02 面试题
火车来了教学反思
2014/02/11 职场文书
任命书范本大全
2014/06/06 职场文书
2014法院四风问题对照检查材料思想汇报
2014/10/04 职场文书
刑事辩护授权委托书格式
2014/10/13 职场文书
本科毕业论文致谢词
2015/05/14 职场文书
导游词之苏州盘门景区
2019/11/12 职场文书
读《人生的智慧》有感:闲暇是人生的精华
2019/12/25 职场文书
Python爬虫数据的分类及json数据使用小结
2021/03/29 Python
html css3不拉伸图片显示效果
2021/06/07 HTML / CSS
Redis主从配置和底层实现原理解析(实战记录)
2021/06/30 Redis