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 live
May 15 Javascript
jQuery$命名冲突怎么办如何解决
Jan 16 Javascript
Javascript学习笔记之相等符号与严格相等符号
Nov 23 Javascript
Javascript HTML5 Canvas实现的一个画板
Apr 12 Javascript
jquery pagination插件动态分页实例(Bootstrap分页)
Dec 23 Javascript
JavaScript仿聊天室聊天记录
Dec 27 Javascript
简单实现bootstrap选项卡效果
Feb 08 Javascript
js获取指定时间的前几秒
Apr 05 Javascript
简单的网页广告特效实例
Aug 19 Javascript
Angular2里获取(input file)上传文件的内容的方法
Sep 05 Javascript
详解vue中使用express+fetch获取本地json文件
Oct 10 Javascript
收集前端面试题之url、href、src
Mar 22 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
解析PHP中一些可能会被忽略的问题
2013/06/21 PHP
Thinkphp中import的几个用法详细介绍
2014/07/02 PHP
详解PHP中的状态模式编程
2015/08/11 PHP
Js的MessageBox
2006/12/03 Javascript
jquery中get和post的简单实例
2014/02/04 Javascript
jquery如何扑捉回车键触发的事件
2014/04/24 Javascript
用javascript读取xml文件读取节点数据
2014/08/12 Javascript
JavaScript数据结构与算法之栈详解
2015/03/12 Javascript
javascript实现3D切换焦点图
2015/10/16 Javascript
js点击文本框后才加载验证码实例代码
2015/10/20 Javascript
JS实现的3D拖拽翻页效果代码
2015/10/31 Javascript
JavaScript数据绑定实现一个简单的 MVVM 库
2016/04/08 Javascript
jQuery on()方法绑定动态元素的点击事件无响应的解决办法
2016/07/07 Javascript
利用jquery实现下拉框的禁用与启用
2016/12/07 Javascript
jquery.guide.js新版上线操作向导镂空提示jQuery插件(推荐)
2017/05/20 jQuery
Express+Nodejs 下的登录拦截实现代码
2017/07/01 NodeJs
Vue实现typeahead组件功能(非常靠谱)
2017/08/26 Javascript
详解vue2.0 使用动态组件实现 Tab 标签页切换效果(vue-cli)
2017/08/30 Javascript
vue iview组件表格 render函数的使用方法详解
2018/03/15 Javascript
JavaScript设计模式之建造者模式实例教程
2018/07/02 Javascript
微信小程序webview实现长按点击识别二维码功能示例
2019/01/24 Javascript
JavaScript命令模式原理与用法实例详解
2020/03/10 Javascript
jQuery实现鼠标滑动切换图片
2020/05/27 jQuery
jQuery 动态粒子效果示例代码
2020/07/07 jQuery
Python生成验证码实例
2014/08/21 Python
浅析Python多线程下的变量问题
2015/04/28 Python
不同版本中Python matplotlib.pyplot.draw()界面绘制异常问题的解决
2017/09/24 Python
Django为窗体加上防机器人的验证码功能过程解析
2019/08/14 Python
Python传递参数的多种方式(小结)
2019/09/18 Python
np.dot()函数的用法详解
2020/01/17 Python
pandas抽取行列数据的几种方法
2020/12/13 Python
美国运动鞋和运动服零售商:Footaction
2017/04/07 全球购物
WiFi云数码相框:Nixplay
2018/07/05 全球购物
《鸟的天堂》教学反思
2014/02/27 职场文书
python实现股票历史数据可视化分析案例
2021/06/10 Python
使用Ajax实现无刷新上传文件
2022/04/12 Javascript