vue--响应式原理(2)
在谈 Vue 响应式原理之前,我们需要先了解一下 ES5 的 Object 的一个属性 defineProperty。
下面我们来看一段官方的介绍
The Object.defineProperty() method defines a new property directly on an object, or modifies an existing property on an object, and returns the object.
直接在一个对象上定义一个新的属性,或修改一个已经存在的属性。这个方法会返回该对象。
语法:
Object.defineProperty(obj, prop, descriptor)
参数说明:
@params obj // 目标对象 type: Obejct @params prop // 需要定义的属性 type: String @params descriptor // 定义的属性所拥有的特性 type: Obejct
通过简单的介绍可以看看到,也就是定义了个对象的某个属性,但是其中的奥秘主要在第三个参数 descriptor。 我们看一下第三个参数可以设置的属性:
- value
- writable
- get ,set
- configurable
- enumerable
分别介绍一下每个属性:
1. value
属性的值, 默认为undefined。例如:
var someOne = {} Object.defineProperty(someOne, 'name', { value : 'cover' }) someOne.name // cover
从表面上看, 貌似和下面的语法是等价的:
someOne.name = 'cover'
那我们继续往下看接下来的属性。
2. writable
该属性是否可写, 如果设置成 false,则任何对该属性改写的操作都无效(但不会报错),默认为 false。
var someOne = { }; Object.defineProperty(someOne, "name", { value:"coverguo" , // 由于设定了writable属性为false 导致这个量不可以修改 writable: false }); console.log(someOne.name); // 输出 coverguo someOne.name = "monkeyWang"; console.log(someOne.name); // 输出coverguo
3. configurable
如果为 false,则任何尝试删除目标属性或修改属性以下特性(writable, configurable, enumerable)的行为将被无效化,默认为 false。
var someOne = { }; Object.defineProperty(someOne, "name", { configurable: false, // 由于设定了configurable属性为false导致所有属性不可修改 value: "hello" }); // 下面的操作想让 configurable 变为 true 但是不会被允许 Object.defineProperty(someOne, "name", { configurable: true, value: "hello" }); // Cannot redefine property: name var someOne = { }; Object.defineProperty(someOne, "name", { configurable: true, // 由于设定了configurable属性为false导致所有属性不可修改 value: "hello" }); // 下面的操作想让 configurable 变为 false 是可以的 Object.defineProperty(someOne, "name", { configurable: false, value: "hello" });
4. enumerable
是否能在for...in循环中遍历出来或在Object.keys中列举出来。默认为 false。
var someOne = {} Object.defineProperty(someOne,"name",{ value:3445, enumerable:true }) console.log(Object.keys(someOne));// 打印["name"]
改为false
var someOne = {} Object.defineProperty(someOne,"name",{ value:3445, enumerable:false //注意咯这里改了 }) console.log(Object.keys(someOne));// 打印[]
for...in 类似,不赘述了。
接下来看看更加关键的几个属性:set 和 get
5. set 和 get
在 descriptor 中不能同时设置访问器(get 和 set)和 wriable 或 value,否则会错,就是说想用 get 和 set,就不能用 writable 或 value 中的任何一个。
set 和 get,他俩干啥用的的。
var someOne= {} Object.defineProperty(someOne,"name",{ set: function (newValue) { console.log('你设置了name,新的值是' + newValue); }, get: function (value) { console.log('你访问了name'); } }) someOne.name = 'monkeyWang'// 你设置了name,新值是monkeyWang console.log(someOne.name) // 你访问了name
简单来说,这个 “b” 赋值或者取值的时候会分别触发 set 和 get 对应的函数。
演习:
了解了上面这么多,那我们便可以开始 Vue 的基本响应式之旅了:我们从最简单的开始。其中,动态数据绑定就是 Vue 最为基础,最为有用的一个功能。这个系列将分成5部分,一步一步来理解和实现这一功能。ok,我们从最简单的开始。给定任意一个对象,如何监听其属性的读取与变化?也就是说,如何知道程序访问了对象的哪个属性,又改变了哪个属性?
let app1 = new Observer({ name: 'youngwind', age: 25 }); let app2 = new Observer({ university: 'bupt', major: 'computer' }); // 要实现的结果如下: app1.data.name // 你访问了 name app.data.age = 100; // 你设置了 age,新的值为100 app2.data.university // 你访问了 university app2.data.major = 'science' // 你设置了 major,新的值为 science
感兴趣的小伙伴可以动手去实现这样一个简单的数据绑定。
如果传入参数对象是一个“比较深”的对象(也就是其属性值也可能是对象),那该怎么办呢?考虑传递回调函数。
在实际应用中,当特定数据发生改变的时候,我们是希望做一些特定的事情的,而不是每一次都只能打印出一些信息。所以,我们如何支持传入回调函数的功能?