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 相关文章推荐
Javascript继承(上)——对象构建介绍
Nov 08 Javascript
js Math 对象的方法
Sep 01 Javascript
jQuery判断checkbox(复选框)是否被选中以及全选、反选实现代码
Feb 21 Javascript
javascript操作excel生成报表全攻略
May 04 Javascript
js获取隐藏元素宽高的实现方法
May 19 Javascript
jQuery Easyui使用(二)之可折叠面板动态加载无效果的解决方法
Aug 17 Javascript
jQuery+Ajax实现用户名重名实时检测
Jun 01 jQuery
深究AngularJS中ng-drag、ng-drop的用法
Jun 12 Javascript
JavaScript实现QQ列表展开收缩扩展功能
Oct 30 Javascript
Egg Vue SSR 服务端渲染数据请求与asyncData
Nov 24 Javascript
JavaScript简单编程实例学习
Feb 14 Javascript
原生js实现购物车功能
Sep 23 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中获取关键词及所属来源搜索引擎名称的代码
2011/02/15 PHP
php插入含有特殊符号数据的处理方法
2016/11/24 PHP
Laravel中日期时间处理包Carbon的简单使用
2017/09/21 PHP
PHP7 安装event扩展的实现方法
2019/10/08 PHP
JavaScript中判断函数是new还是()调用的区别说明
2011/04/07 Javascript
ExtJs默认的字体大小改变的几种方法(自己整理)
2013/04/18 Javascript
js与jquery获取父元素,删除子元素的两种不同方法
2014/01/09 Javascript
页面加载完毕后滚动条自动滚动一定位置
2014/02/20 Javascript
原生javascript实现Tab选项卡切换功能
2015/01/12 Javascript
解决node.js安装包失败的几种方法
2016/09/02 Javascript
JS实现针对给定时间的倒计时功能示例
2017/04/11 Javascript
为vue-router懒加载时下载js的过程中添加loading提示避免无响应问题
2018/04/03 Javascript
详解Vue中watch的高级用法
2018/05/02 Javascript
JavaScript强制类型转换和隐式类型转换操作示例
2019/05/01 Javascript
JS求1到任意数之间的所有质数的方法详解
2019/05/20 Javascript
vue中添加与删除关键字搜索功能
2019/10/12 Javascript
[03:51]吞吞映像 每周精彩击杀top10第二弹
2014/06/25 DOTA
Python中Django框架利用url来控制登录的方法
2015/07/25 Python
Python中基础的socket编程实战攻略
2016/06/01 Python
Win10下Python环境搭建与配置教程
2016/11/18 Python
Python+matplotlib绘制不同大小和颜色散点图实例
2018/01/19 Python
Pandas 缺失数据处理的实现
2019/11/04 Python
Python 用turtle实现用正方形画圆的例子
2019/11/21 Python
解决Python spyder显示不全df列和行的问题
2020/04/20 Python
Python 通过监听端口实现唯一脚本运行方式
2020/05/05 Python
Python本地及虚拟解释器配置过程解析
2020/10/13 Python
HTML5中在title标题标签里设置小图标的方法
2020/06/23 HTML / CSS
皮尔·卡丹巴西官方商店:Pierre Cardin
2017/07/21 全球购物
The North Face北面英国官网:美国著名户外品牌
2017/12/13 全球购物
ESDlife健康生活易:身体检查预订、搜寻及比较
2019/05/10 全球购物
平面网站制作专科生的自我评价分享
2013/12/11 职场文书
教育技术职业规划范文
2014/03/04 职场文书
争做文明公民倡议书
2014/08/29 职场文书
先进工作者事迹材料
2014/12/23 职场文书
Java实现聊天机器人完善版
2021/07/04 Java/Android
Spark SQL 2.4.8 操作 Dataframe的两种方式
2021/10/16 SQL Server