说说响应式原理中哪些让你"卧槽"的知识点

说说响应式原理中哪些让你"卧槽"的知识点

你真的了解响应式原理么?

    响应式原理在平时面试中十之八九会被问到,在面对这个问题时候,我们大多数能想到的就是对Object.defindeProperty侃侃而谈,确实Vue 的响应式原理是核心是通过 ES5 的保护对象的Object.defindeProperty 中的访问器属性中的 getset 方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化;但是问自己几个小问题:

  1. 对象和数组是如何进行检测
  2. 数组中的pushpopshiftunshiftreversesortsplice原生方法又是如何做到新增数据的检测的
  3. 数组又是如何进行替代索引赋值的

    如果你还有点迷糊,请认真阅读我之前写的一篇文章vue响应式原理以及依赖收集;这篇文章就不来细说,就谈谈几个让人为之一震的知识点。

让你‘卧槽’的vue响应式原理知识点

  • 数组方法的劫持

    在Vue中我们在处理数组的时候劫持了数组原生的一些方法,从而达到对数组各个元素进行检测;那么是如何进行劫持的呢?vue很巧妙的重写了数组的原型方法;具体做法如下:
let oldArrayProtoMethods = Array.prototype;
export let arrayMethods = Object.create(oldArrayProtoMethods);
let methods = [
    'push',
    'pop',
    'shift',
    'unshift',
    'reverse',
    'sort',
    'splice'
];
methods.forEach(method => {
    arrayMethods[method] = function (...args) {
        const result = oldArrayProtoMethods[method].apply(this, args);
        const ob = this.__ob__;
        let inserted;
        switch (method) {
            case 'push':
            case 'unshift':
                inserted = args;
                break;
            case 'splice':
                inserted = args.slice(2)
            default:
                break;
        }
        if (inserted) ob.observeArray(inserted); // 对新增的每一项进行观测
        return result
    }
})

    想要更详细点的可参考我之前写的一篇文章vue中数组的一些方法是如何进行试图更新的;

  • __ob__的“跨域”相联;

        前面提到的我们在做数组的检测时会重写这个原型方法,在vue源码中这个作为了一个单独模块;那么就有了值得思考的问题,就是我们在重写原型方法模块如何调用Observe类里的observeArray方法进行检测?Vue中很巧妙的在观测的对象中加入一个__ob__属性,指向当前这个Observe实例,这样每个响应式数据就可以访问 Observe实例上的方法了;
  • 使用Object.defineProperty增加__ob__;
 Object.defineProperty(value,'__ob__',{
        enumerable:false,
        configurable:false,
        value:this
});

    试想下如果没有设置不可枚举,那么在递归进行响应式检测的时候就会无限循环了;所以要排除掉添加了__ob__的检测对象;

写在最后

    你有感觉到'卧槽'了么?

    参考文章;

posted @ 2020-06-10 14:17  Devin_n  阅读(153)  评论(0编辑  收藏  举报