Vue 的响应式系统原理
Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript
对象。而当你修改它们时,视图会进行更新。
当你把javascript对象传给vue实例的data属性的时候,Vue 将遍历此对象所有的属性,通过 Object.defineProperty
来给每个属性都添加 getter
和 setter
.
而每个组件实例又都有一个watcher
对象,它会将组件渲染过程中的属性渲染为【依赖】,当数据发生变化的时候,会触发setter
,会通知 watcher
重新计算,从而致使它关联的组件得以更新。
一、Object.defineProperty
Object.defineProperty()
方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象。
Object.defineProperty(obj, prop, descriptor)
参数
-
obj
需要定义属性的对象。 -
prop
需被定义或修改的属性名。 -
descriptor
需被定义或修改的属性的描述符。
Object.defineProperty(obj, "key", {
enumerable: false, // 不可枚举
configurable: false, // 不可更改
writable: false, // 不可被赋值运算符改变
value: "static"
})
// 创建属性
var o = {};
Object.defineProperty(o, 'a', {
enumerable: true,
configurable: true,
writable: true,
value: 17
});
// 对象o拥有了属性a,值为17
var bValue = 38;
Object.defineProperty(o, 'b', {
get: function() { return bValue; },
set: function(newValue) { bValue = newValue; },
enumerable: true,
configurable: true
});
o.b; // 38
- Writable 属性
var o = {}; // 创建一个新对象
Object.defineProperty(o, "a", { value : 37,
writable : false });
console.log(o.a); // 打印 37
o.a = 25; // 没有错误抛出(在严格模式下会抛出,即使之前已经有相同的值)
console.log(o.a); // 打印 37, 赋值不起作用。
- Enumerable 特性
var o = {};
Object.defineProperty(o, "a", { value : 1, enumerable:true });
Object.defineProperty(o, "b", { value : 2, enumerable:false });
Object.defineProperty(o, "c", { value : 3 }); // enumerable defaults to false
o.d = 4; // 如果使用直接赋值的方式创建对象的属性,则这个属性的enumerable为true
for (var i in o) {
console.log(i);
}
// 打印 'a' 和 'd' (in undefined order)
Object.keys(o); // ["a", "d"]
o.propertyIsEnumerable('a'); // true
o.propertyIsEnumerable('b'); // false
o.propertyIsEnumerable('c'); // false
- Configurable 特性
configurable
特性表示对象的属性是否可以被删除,以及除 writable 特性外的其他特性是否可以被修改。
Object.defineProperty(person,'a',{
configurable:false,//为false的时候不允许修改默认属性了
})
===============================
# 改为false之后再试试修改其他属性
Object.defineProperty(person,'a',{
configurable:true,
enumerable:true,
writable:true,
value:1
})
//woa,控制台直接报错了!连想把false值改回true都不行!也就是说,这个改动是一次性了!
//也就是说,你可以使用Object.defineProperty()方法无限修改同一个属性,但是当把configurable改为false之后就有限制了
1 、首先定义一个cb函数,这个函数用来模拟试图更新。
//
function cb (val) {
/* 渲染视图 */
console.log("视图更新啦~");
}
2、 定义一个defineReactive ,这个方法通过 Object.defineProperty
来实现对对象的「响应式」化,入参是一个 obj(需要绑定的对象)
、key(obj的某一个属性)
,val(具体的值)
。
function defineReactive(obj, key, val){
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function(){
return val;
},
set:function(newVal) {
if (newVal === val) return;
cb(newVal);
}
})
}
// 当一个对象,赋值给Vue实力的data选项的时候,就会触发该操作,对数据进行响应化处理
3、 当然这是不够的,我们需要在上面再封装一层 observer 。这个函数传入一个 value(需要「响应式」化的对象),通过遍历所有属性的方式对该对象的每一个属性都通过 defineReactive 处理
。
function observer(val)
{
if(!val || typeof val != 'object') {
return ;
}
Object.keys(val).forEach((key)=> {
defineReactive(val,key, val[key]);
})
}
4、 在 Vue 的构造函数中,对 options 的 data 进行处理
class Vue {
/* Vue构造类 */
constructor(options) {
this._data = options.data;
observer(this._data);
}
}
5、 这样我们只要 new 一个 Vue 对象,就会将 data 中的数据进行「响应式」化。如果我们对 data 的属性进行下面的操作,就会触发 cb 方法更新视图。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。