vue2数据响应式原理
目录
- Object.defineProperty() 方法
- defineReactive函数
- 递归侦测对象全部属性
Object.defineProperty() 方法
- Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
const object1 = {};
// 在object1对象上定义property1属性的值value为42
Object.defineProperty(object1, 'property1', {
value: 42// value代表属性的值
});
object1.property1 = 77;// 默认不能改变属性值
console.log(object1.property1);// 42
- 为什么要用Object.defineProperty() 方法 你用
object1.property1=42
不是更简洁吗:我们可以使用Object.defineProperty() 方法来定义一些隐藏的属性
(1)writable:当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符 改变。默认为 false。
const object1 = {};
Object.defineProperty(object1, 'property1', {
value: 42,
writable: true
});
object1.property1 = 77;
console.log(object1.property1);// 77
(2)enumerable:当且仅当该属性的 值为 true 时,该属性才会出现在对象的枚举属性中 才可以用for…in…遍历。默认为 false。
- get:属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。默认为 undefined。
set:属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。默认为 undefined。
const object1 = {};
Object.defineProperty(object1, 'property1', {
value: 42// value代表属性的值
});
Object.defineProperty(object1, 'property2', {
get(){
console.log('你在访问object1的property2属性')
},
set(){
console.log('你在设置object1的property2属性')
}
});
console.log(object1);// property1: 42因为你没给property2赋值
object1.property2 = 10;
// 你在访问object1的property2属性
// 你在设置object1的property2属性
console.log(object1.property2)// undefined
defineReactive函数
getter函数的返回值会被用作属性的值 setter函数接受一个参数(也就是被赋予的新值)
const object1 = {};
Object.defineProperty(object1, 'property2', {
get(){
console.log('你在访问object1的property2属性')
return 7;
},
set(newValue){
console.log('你在设置object1的property2属性', newValue)
}
});
console.log(object1.property2)// 7
object1.property2 = 10;
// 你在访问object1的property2属性
// 你在设置object1的property2属性 10
console.log(object1.property2)// 7
为什么返回7而不是10 我明明给object1.property2赋新值了 因为getter中并不能返回你刚修改的值 你只要一访问object1.property2 就会调用get() 返回7 为了解决这个问题 我们需要用一个变量来周转一下
const object1 = {};
let temp;
Object.defineProperty(object1, 'property2', {
get(){
console.log('你在访问object1的property2属性')
return temp;// 用到闭包
},
set(newValue){
console.log('你在设置object1的property2属性', newValue)
temp = newValue;// 用到闭包
}
});
console.log(object1.property2)// undefined
object1.property2 = 10;
// 你在访问object1的property2属性
// 你在设置object1的property2属性 10
console.log(object1.property2)// 10
Object.defineProperty需要变量周转才能使用setter getter 我们把变量和Object.defineProperty封装一下
const object1 = {};
// data:对象 key:对象的属性 val:变量
function defineReactive(data, key, val){
Object.defineProperty(data, key, {
get(){
console.log('你在访问object1的property2属性')
return val;// 用到闭包
},
set(newValue){
console.log('你在设置object1的property2属性', newValue)
if(val === newValue) return;
val = newValue;// 用到闭包
},
// 你也可以在里面配置一些属性
enumerable: true;
configurable: true
});
}
defineReactive(object1, property2, 7)
console.log(object1.property2)// 7
object1.property2 = 10;
console.log(object1.property2)// 10
defineReactive函数提供了闭包 你可以不另外使用临时变量来使用setter getter
递归侦测对象全部属性
上面只能让property2中的值实现响应式 如果property2是个对象 a中的对象的值其实不能实现响应式的 不能进行get set 下面我们来实现一个类Observer 它可以将一个正常的object转换为每个层级的属性都是响应式的(可以被侦测到)的object 思路如下图
- 创建一个类 你要想的第一件事:该类如何被实例化