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 相关文章推荐
仅IE支持clearAttributes/mergeAttributes方法使用介绍
May 04 Javascript
JS字符串累加Array不一定比字符串累加快(根据电脑配置)
May 14 Javascript
extjs 04_grid 单击事件新发现
Nov 27 Javascript
javascript实现动态加载CSS
Jan 26 Javascript
获取阴历(农历)和当前日期的js代码
Feb 15 Javascript
浅析Bootstrap验证控件的使用
Jun 23 Javascript
JS HTML5拖拽上传图片预览
Jul 18 Javascript
详解AngularJS 路由 resolve用法
Apr 24 Javascript
Node.js调用fs.renameSync报错(Error: EXDEV, cross-device link not permitted)
Dec 27 Javascript
微信小程序bindinput与bindsubmit的区别实例分析
Apr 17 Javascript
基于JQuery和DWR实现异步数据传递
Oct 16 jQuery
Vue常用API、高级API的相关总结
Feb 02 Vue.js
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截取中文字符串的问题
2006/07/12 PHP
PHP动态规划解决0-1背包问题实例分析
2015/03/23 PHP
基于ThinkPHP+uploadify+upload+PHPExcel 无刷新导入数据
2015/09/23 PHP
关于IFRAME 自适应高度的研究
2006/07/20 Javascript
jquery1.4后 jqDrag 拖动 不可用
2010/02/06 Javascript
window.location.hash 使用说明
2010/11/08 Javascript
javascript学习笔记(十) js对象 继承
2012/06/19 Javascript
侧栏跟随滚动的简单实现代码
2013/03/18 Javascript
JS实现金额转换(将输入的阿拉伯数字)转换成中文的实现代码
2013/09/30 Javascript
把字符串按照特定的字母顺序进行排序的js代码
2014/01/28 Javascript
在css加载完毕后自动判断页面是否加入css或js文件
2014/09/10 Javascript
利用jQuery设计一个简单的web音乐播放器的实例分享
2016/03/08 Javascript
Javascript闭包与函数柯里化浅析
2016/06/22 Javascript
JS简单去除数组中重复项的方法
2016/09/13 Javascript
VueJs路由跳转——vue-router的使用详解
2017/01/10 Javascript
bootstrap 表单验证使用方法
2017/01/11 Javascript
利用Node.js对文件进行重命名
2017/03/12 Javascript
JavaScript转换数据库DateTime字段类型方法
2017/06/27 Javascript
关于Vue Webpack2单元测试示例详解
2017/08/14 Javascript
解决VUE框架 导致绑定事件的阻止冒泡失效问题
2018/02/24 Javascript
vue2.0 如何在hash模式下实现微信分享
2019/01/22 Javascript
解决layui弹出层layer的area过大被遮挡的问题
2019/09/21 Javascript
Vue组件通信中非父子组件传值知识点总结
2019/12/05 Javascript
python实现多线程采集的2个代码例子
2014/07/07 Python
基于python爬虫数据处理(详解)
2017/06/10 Python
解决Python正则表达式匹配反斜杠''\''问题
2019/07/17 Python
PHP统计代码行数的小代码
2019/09/19 Python
详解python安装matplotlib库三种失败情况
2020/07/28 Python
Restful_framework视图组件代码实例解析
2020/11/17 Python
DC Shoes荷兰官方网站:美国极限运动品牌
2019/10/22 全球购物
英国最大的割草机购买网站:Just Lawnmowers
2019/11/02 全球购物
工作违纪检讨书
2014/02/17 职场文书
村级四风对照检查材料
2014/08/24 职场文书
导游词之安徽巢湖
2019/12/26 职场文书
详解CocosCreator项目结构机制
2021/04/14 Javascript
python和Appium的移动端多设备自动化测试框架
2022/04/26 Python