LearnVue 响应式原理

Vue.js的响应式原理依赖于 Object.defineProperty,尤大大在 Vue.js文档 中就已经提到过,这也是 Vue.js 不支持 IE8 以及更低版本浏览器的原因。Vue 通过设定对象属性的 setter/getter 方法来监听数据的变化,通过 getter 进行依赖收集,而每个 setter 方法就是一个观察者,在数据变更的时候通知订阅者更新视图。

将数据data变成可观察(observable)的

注解

  • Object.defineProperty( obj, propName, descriptor )

    在对象上定义一个新的属性,或者修改一个存在的属性,然后返回该对象

    其中 descriptor 有以下参数

    描述符 作用 默认值
    configurable 是否 可更改属性类型和可删除 false
    enumerable 是否 可枚举属性该属性。如果为 true, 在枚举属性的时候,会显示该属性 false
    vlue 属性的值, 可以是任意的 js 值类型 undefined
    writable 是否 属性值是否可以通过赋值运算符进行修改 false
    get 存取器 undefined
    set 存取器 undefined
  • Object.keys()

    返回对象所有的属性

疑问?

1
2
3
4
5
6
class Vue {
constructor(options) {
this._data = options.data;
observe(this._data, options.render)
}
}

如果是 component ,它的 data 是一个函数,那它的 data 是怎么处理的呢?

代理

我们可以在Vue的构造函数constructor中为data执行一个代理proxy。这样我们就把data上面的属性代理到了vm实例上。

  • call()

    使用给定的 this 值和单独提供的参数调用函数。

    这样,在 _proxy 函数里面就可以调用 this 值了。

问题?

为什么不直接将 data 中的参数定义到 vm (vue 的实例) 上,而是要先定义到 vm._data, 然后再代理到 vm 呢?

我猜测是因为:

  • 如果直接定义到 this 实例上,那 data 就没有定义
  • 而通过代理,data 传递引用给 vm._data, 在 _data上定义,就代表在 data 上也定义了,然后再代理到 vm 上,这样,可以通过 vm.propertyName 访问了

后记

本文是在学习 LearnVue 时的个人注解,如果需要参考,请先阅读 LearnVue