关于 Vue.js
Vue.js 是一款 MVVM 框架,上手快速简单易用,通过响应式在修改数据的时候更新视图。当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。Vue 通过设定对象属性的 setter/getter 方法来监听数据的变化,通过 getter 进行依赖收集,而每个 setter 方法就是一个观察者,在数据变更的时候通知订阅者更新视图。
使 Object 数据变成可观察(observable)的
首先定义一个对象 person:
1 2 3 4
| var person = { name: "张三", age: 18, };
|
然后我们通过 Object.defineProperty 来改写这个对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| var person = {}; var name = "张三"; Object.defineProperty(person, "name", { enumerable: true, configurable: true, get() { console.log("name属性被读取了"); return name; }, set(newVal) { console.log("name属性被修改了"); name = newVal; }, }); console.log(person.name); person.name = "李四";
|
通过 Object.defineProperty()方法给 person 定义了一个 name 属性,并把这个属性的读和写分别使用 get()和 set()进行拦截,每当该属性进行读或写操作的时候就会触发 get()和 set()。
那么 Vue 是如何将所有 data 下面的所有属性变成可观察的(observable)呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
|
function def(obj, key, val, enumerable) { Object.defineProperty(obj, key, { value: val, enumerable: !!enumerable, writable: true, configurable: true, }); }
class Observer { constructor(value) { this.value = value; def(value, "__ob__", this); if (Array.isArray(value)) { } else { this.walk(value); } }
walk(obj) { const keys = Object.keys(obj); for (let i = 0; i < keys.length; i++) { defineReactive(obj, keys[i]); } } }
function defineReactive(obj, key, val) { if (arguments.length === 2) { val = obj[key]; } if (typeof val === "object") { new Observer(val); } Object.defineProperty(obj, key, { enumerable: true, configurable: true, get() { console.log(`${key}属性被读取了`); return val; }, set(newVal) { if (val === newVal) { return; } console.log(`${key}属性被修改了`); val = newVal; }, }); }
let person = new Observer({ name: "张三", age: 18, });
person.value.name; person.value.name = "李四";
|
在上面的代码中,我们定义了 Observer 类,它用来将一个正常的 object 转换成可观测的 object。
并且给 value 新增一个ob属性,值为该 value 的 Observer 实例。这个操作相当于为 value 打上标记,表示它已经被转化成响应式了,避免重复操作
然后判断数据的类型,只有 object 类型的数据才会调用 walk 将每一个属性转换成 getter/setter 的形式来侦测变化。 最后,在 defineReactive 中当传入的属性值还是一个 object 时使用 new observer(val)来递归子属性,这样我们就可以把 obj 中的所有属性(包括子属性)都转换成 getter/seter 的形式来侦测变化。 也就是说,只要我们将一个 object 传到 observer 中,那么这个 object 就会变成可观测的、响应式的 object。
参考文献