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简化JavaScript开发分析
Feb 19 Javascript
js判断字符长度以及中英文数字等
Dec 31 Javascript
通过JS来动态的修改url,实现对url的增删查改
Sep 01 Javascript
浅谈javascript回调函数
Dec 07 Javascript
Jquery日期选择datepicker插件用法实例分析
Jun 08 Javascript
把Node.js程序加入服务实现随机启动
Jun 25 Javascript
React通过父组件传递类名给子组件的实现方法
Nov 13 Javascript
Angular实现的简单定时器功能示例
Dec 28 Javascript
Vue组件内部实现一个双向数据绑定的实例代码
Apr 04 Javascript
通过GASP让vue实现动态效果实例代码详解
Nov 24 Javascript
vue-cli在 history模式下的配置详解
Nov 26 Javascript
React中获取数据的3种方法及优缺点
Feb 18 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
windows xp下安装pear
2006/12/02 PHP
Zend studio for eclipse中使php可以调用mysql相关函数的设置方法
2008/10/13 PHP
解析在zend Farmework下如何创立一个FORM表单
2013/06/28 PHP
php使用curl获取https请求的方法
2015/02/11 PHP
PHP的new static和new self的区别与使用
2019/11/27 PHP
利用javascript实现全部删或清空所选的操作
2014/05/27 Javascript
JS是按值传递还是按引用传递
2015/01/30 Javascript
JavaScript实现向OL列表内动态添加LI元素的方法
2015/03/21 Javascript
使用AngularJS制作一个简单的RSS阅读器的教程
2015/06/18 Javascript
Angularjs 滚动加载更多数据
2016/03/17 Javascript
常用的js方法合集
2017/03/10 Javascript
NodeJS 实现手机短信验证模块阿里大于功能
2017/06/19 NodeJs
jQuery实现点击DIV同时点击CheckBox,并为DIV上背景色的实例
2017/12/18 jQuery
trackingjs+websocket+百度人脸识别API实现人脸签到
2018/11/26 Javascript
基于Fixed定位的框选功能的实现代码
2019/05/13 Javascript
vue实现直播间点赞飘心效果的示例代码
2019/09/20 Javascript
vue组件传值的实现方式小结【三种方式】
2020/02/05 Javascript
[01:43]3.19DOTA2发布会 三代刀塔人第三代
2014/03/25 DOTA
浅谈Python 的枚举 Enum
2017/06/12 Python
Python获取当前函数名称方法实例分享
2018/01/18 Python
Python OpenCV获取视频的方法
2018/02/28 Python
python Pillow图像处理方法汇总
2019/10/16 Python
使用matplotlib绘制图例标签中带有公式的图
2019/12/13 Python
Pycharm的Available Packages为空的解决方法
2020/09/18 Python
CSS3教程:新增加的结构伪类
2009/04/02 HTML / CSS
飞利浦西班牙官方网站:Philips西班牙
2020/02/17 全球购物
华为慧通笔试题
2016/04/22 面试题
自荐信格式
2013/12/01 职场文书
大学信息公开实施方案
2014/03/09 职场文书
小学生综合素质评语
2014/04/23 职场文书
英语教师求职信
2014/06/16 职场文书
庆元旦主持词
2015/07/06 职场文书
实习感想范文
2015/08/10 职场文书
写作技巧:怎样写好一份优秀工作总结?
2019/08/14 职场文书
配置Kubernetes外网访问集群
2022/03/31 Servers
前端框架ECharts dataset对数据可视化的高级管理
2022/12/24 Javascript