zoukankan      html  css  js  c++  java
  • 【每日一题】【vue2源码学习】vue如何检测数组的变化

    数组可以用defineProperty进行监听。但是考虑性能原因,不能数组一百万项每一项都循环监听(那样性能太差了)。所以没有使用Ojbect.defineProperty对数组每一项进行拦截,而是选择劫持数组原型上的个别方法并重写。

    具体重写的有:

    pushpopshiftunshiftsortreversesplice (这七个都是会改变原数组的)

    另外要注意的是:

    不是直接粗暴重写了Array.prototype上的push等方法,而是通过原型链继承与函数劫持进行的移花接木。并且只监听调用了defineReactive函数时传进来的数组。

    具体实现思路:

    以push为例,而是利用Object.create(Array.prototype)生成新的数组对象,该对象的__proto__指向Array.prototype。并在对象身上创建push等函数,利用函数劫持,在函数内部Array.prototype.push.call调用原有push方法,并执行自己劫持的代码(如视图更新)。最后将需要绑定的数组的__proto__由指向Array.prototype改向指成拥有重写方法的新数组对象。具体看下边源码仿写,真实Array.prototype里的祖宗级别push等方法没有动。

    思考:

    为啥不重写map等也是修改原数组的方法呢?

    特别注意:

    在Vue中修改数组的索引和长度,是无法被监控到并做响应式视图更新的。需要通过以上7种变异方法修改数组才会触发数组对应watcher进行更新。
    数组中如果是对象数据类型的也会进行递归劫持。
    如果情节需要,通过索引来修改数组里的内容。可以通过Vue.$set()方法来进行处理,或者使用splice方法实现。(其实$set内部的核心也是splice方法)

    原理mock:

    vue【数组】响应式数据原理mock

    let state = [1,2,3]; //待监听的数据
    
    // 1、响应式数据-函数劫持实现数组原型方法重写
    let OriginalArray = Array.prototype; // 并不是直接改写原型上的方法。而是给当前待监听的数组原型链上加了push等方法劫持了Array原型的push方法。
    let arrayMethods = Object.create(OriginalArray) // 创建一个新对象(对象or数组由第一个参数决定),带着指定的原型对象(Array.prototype)
    console.log(
      arrayMethods,
       // 原型修改
      arrayMethods.__proto__ === OriginalArray,
      arrayMethods.__proto__ === Array.prototype
    )
    function defineReactive(obj) {
      // 【函数劫持】改写这个新对象身上的push、splice等数组方法
      arrayMethods.push = function(...args){
        // 并还是调用原生的push方法
        OriginalArray.push.apply(this, args) // 或者用call(this, ...args)
        // 然后这里边做自己的事情,比如视图更新(具体源码怎么更新的视图?)
        render()
      }
      // 
      obj.__proto__ = arrayMethods // 修改传进来的、被监听的数组的原型链,链接数组与被重写的方法。原本__proto__指向Array.prototype,现在中间给他包了一层,指向我们重写的原型方法。并在重写的原型方法里再调用Array.prototype的同名原型方法。
    }
    defineReactive(state);
    // 操作dom
    function render() {
      app.innerHTML = state;
    }
    render()
    // 更改数据,观察dom修改
    btn.onclick = () => {
      state.push(state[state.length - 1] + 1)
    }
    

    源码位置:

    github:src/core/observer/array.js:8

    本文使用 mdnice 排版

  • 相关阅读:
    Eclipse / android studio 添加第三方jar包 步骤
    Android checkbox 自定义点击效果
    Android 程序打包和安装过程
    Android 基础
    (转)Genymotion安装virtual device的“unable to create virtual device, Server returned Http status code 0”的解决方法
    (转)eclipse 导入Android 项目 步骤
    微信开放平台注册 步骤
    Android Studio 初级安装
    数组
    作用域问题代码
  • 原文地址:https://www.cnblogs.com/padding1015/p/13744239.html
Copyright © 2011-2022 走看看