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 相关文章推荐
jquery 简单导航实现代码
Sep 11 Javascript
jQuery+CSS实现菜单滑动伸展收缩(仿淘宝)
Mar 22 Javascript
DOM节点深度克隆函数cloneNode()用法实例
Jan 12 Javascript
js实现可得到不同颜色值的颜色选择器实例
Feb 28 Javascript
JavaScript中的return语句简单介绍
Dec 07 Javascript
jQuery EasyUi 验证功能实例解析
Jan 06 Javascript
AngularJs 利用百度地图API 定位当前位置 获取地址信息
Jan 18 Javascript
Ajax高级笔记 JavaScript高级程序设计笔记
Jun 22 Javascript
Vue.js实现数据响应的方法
Aug 13 Javascript
JavaScript实现的开关灯泡点击切换特效示例
Jul 08 Javascript
在博客园博文中添加自定义右键菜单的方法详解
Feb 05 Javascript
vue点击按钮实现简单页面的切换
Sep 08 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
我的论坛源代码(六)
2006/10/09 PHP
编写PHP脚本过滤用户上传的图片
2015/07/03 PHP
php结合web uploader插件实现分片上传文件
2016/05/10 PHP
PHP绕过open_basedir限制操作文件的方法
2018/06/10 PHP
JS控制表格隔行变色
2006/06/26 Javascript
Tab页界面 用jQuery及Ajax技术实现(php后台)
2011/10/12 Javascript
js性能优化 如何更快速加载你的JavaScript页面
2012/03/17 Javascript
js获取url中的参数且参数为中文时通过js解码
2014/03/19 Javascript
AngularJS中取消对HTML片段转义的方法例子
2015/01/04 Javascript
详解A标签中href=&quot;&quot;的几种用法
2017/08/20 Javascript
原生js实现简单的模态框示例
2017/09/08 Javascript
React-Router如何进行页面权限管理的方法
2017/12/06 Javascript
JS中数据结构之栈
2019/01/01 Javascript
Vue formData实现图片上传
2019/08/20 Javascript
微信小程序调用wx.getImageInfo遇到的坑解决
2020/05/31 Javascript
Vue切换div显示隐藏,多选,单选代码解析
2020/07/14 Javascript
[02:11]2016国际邀请赛中国区预选赛最美TA采访现场玩家
2016/06/28 DOTA
[01:00:14]DOTA2官方TI8总决赛纪录片 真视界True Sight
2019/01/16 DOTA
关于Python中Inf与Nan的判断问题详解
2017/02/08 Python
python 函数传参之传值还是传引用的分析
2017/09/07 Python
使用Python+wxpy 找出微信里把你删除的好友实例
2019/02/21 Python
python使用PyQt5的简单方法
2019/02/27 Python
python实现PID算法及测试的例子
2019/08/08 Python
Python中函数的返回值示例浅析
2019/08/28 Python
python中sort sorted reverse reversed函数的区别说明
2020/05/11 Python
Python接口测试文件上传实例解析
2020/05/22 Python
html5新特性与用法大全
2018/09/13 HTML / CSS
世界领先的高品质定制产品平台:Zazzle
2017/07/23 全球购物
英国山地公路自行车商店:Tweeks Cycles
2018/03/16 全球购物
DJI大疆德国官方商城:大疆无人机
2018/09/01 全球购物
印尼第一大家居、生活和家具电子商务:Ruparupa
2019/11/25 全球购物
优秀实习生感言
2014/03/01 职场文书
创建卫生先进单位实施方案
2014/03/10 职场文书
学校校庆演讲稿
2014/05/22 职场文书
担保书范文
2019/07/09 职场文书
使用Apache Camel表达REST服务的方法
2022/06/10 Servers