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 相关文章推荐
excel操作之Add Data to a Spreadsheet Cell
Jun 12 Javascript
jquery api参考 visualjquery 中国线路 速度快
Nov 30 Javascript
模仿JQuery sortable效果 代码有错但值得看看
Nov 05 Javascript
Jqgrid设置全选(选择)及获取选择行的值示例代码
Dec 28 Javascript
JavaScript中的值类型详细介绍
Dec 29 Javascript
javascript js 操作数组 增删改查的简单实现
Jun 20 Javascript
微信小程序实现添加手机联系人功能示例
Nov 30 Javascript
Node.js搭建小程序后台服务
Jan 03 Javascript
vue拦截器实现统一token,并兼容IE9验证功能
Apr 26 Javascript
浅谈layui分页控件field参数接收对象的问题
Sep 20 Javascript
基于js实现逐步显示文字输出代码实例
Apr 02 Javascript
vue+spring boot实现校验码功能
May 27 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
DW中链接mysql数据库时,建立字符集中文出现乱码的解决方法
2010/03/27 PHP
PHP中用正则表达式清除字符串的空白
2011/01/17 PHP
zf框架的registry(注册表)使用示例
2014/03/13 PHP
详谈配置phpstorm完美支持Codeigniter(CI)代码自动完成(代码提示)
2017/04/07 PHP
深入浅析PHP的session反序列化漏洞问题
2017/06/15 PHP
js限制文本框为整数和货币的函数代码
2010/10/13 Javascript
javascript smipleChart 简单图标类
2011/01/12 Javascript
基于jquery的返回顶部效果(兼容IE6)
2011/01/17 Javascript
html组件不可输入(只读)同时任何组件都有效
2013/04/01 Javascript
关于textarea提交的内容无法换行的解决办法
2013/04/09 Javascript
使用js正则控制input标签只允许输入的值
2013/07/29 Javascript
jQuery中对未来的元素绑定事件用bind、live or on
2014/04/17 Javascript
JavaScript实现简单的拖动效果
2016/07/02 Javascript
JS实现页面载入时随机显示图片效果
2016/09/07 Javascript
用v-html解决Vue.js渲染中html标签不被解析的问题
2016/12/14 Javascript
Vue常用指令V-model用法
2017/03/08 Javascript
简单实现js进度条加载效果
2020/03/25 Javascript
vue-router2.0 组件之间传参及获取动态参数的方法
2017/11/10 Javascript
jQuery中可见性过滤器简单用法示例
2018/03/31 jQuery
基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析
2020/12/30 Vue.js
Python使用jsonpath-rw模块处理Json对象操作示例
2018/07/31 Python
numpy中的ndarray方法和属性详解
2019/05/27 Python
简单了解django缓存方式及配置
2019/07/19 Python
使用pip安装python库的多种方式
2019/07/31 Python
Python使用get_text()方法从大段html中提取文本的实例
2019/08/27 Python
HTML5 Canvas概述
2009/08/26 HTML / CSS
html5拍照功能实现代码(htm5上传文件)
2013/12/11 HTML / CSS
诗狄娜化妆品官方网站:Stila Cosmetics
2016/12/21 全球购物
法国珠宝店:CLEOR
2017/01/29 全球购物
Bose加拿大官方网站:美国知名音响品牌
2019/03/21 全球购物
机械设计制造专业个人求职信
2013/09/25 职场文书
学习党的群众路线实践活动思想汇报
2014/09/12 职场文书
国家领导干部党的群众路线教育实践活动批评与自我批评材料
2014/09/23 职场文书
执法作风整顿剖析材料
2014/10/11 职场文书
勇敢的心观后感
2015/06/09 职场文书
Golang并发操作中常见的读写锁详析
2021/08/30 Golang