Vue2 响应式原理
vue2 的响应式也就是我们熟知的数据劫持,数据劫持到底是怎么实现的呢?
既然是劫持,肯定有一个源对象和一个劫持对象,那咱们先声明一个源对象 person 和 一个劫持对象 P
let person = {
name: 'ikun',
age: 18
};
let p = {};
vue2 响应式的原理就是通过 definedProperty 给 p 赋值,如果获取 p 的值则返回 person 的对应属性,如果是修改,则是将新的值赋值给 person
先对 person 开启劫持
Object.defineProperty(p, 'name', {
});
Object.defineProperty() 方法接收三个参数,第一个是 target 目标对象,第二个是 value 劫持属性,第三个是 description 描述,实现劫持,需要使用 decription 中的 set 和 get 方法
Object.defineProperty(p, 'name', {
get() {
},
set(val) {
}
});
Object.defineProperty(p, 'age', {
get() {
},
set(val) {
}
});
当劫持对象 p 中的属性或者方法被枚举的时候会调用get,当 P 中的属性或者方法被修改的时候,会调用 set
let person = {
name: 'ikun',
age: 18
};
let p = {};
Object.defineProperty(p, 'name', {
// 访问时会调用 getter
get() {
console.log('我被调用了')
// 被调用的时候做些什么事
return person.name;
},
// 修改时会调用 setter
set(val) {
console.log('我被修改了')
// 被修改的时候做些什么事
person.name = val;
}
});
Object.defineProperty(p, 'age', {
// 访问时会调用 getter
get() {
console.log('我被调用了')
// 被调用的时候做些什么事
return person.age
},
// 修改时会调用 setter
set(val) {
console.log('我被修改了')
// 被修改的时候做些什么事
person.age = val
}
});
set 方法有一个参数,就是被劫持对象的数据的新值,但是对于不存在或者不可枚举的属性无法劫持到,所以这就是为什么再 Vue2 中添加删除数组元素或者对象属性无法立即响应的原因
vue3 响应式原理
区别于 Vue2 的数据劫持 Object.defineProperty,Vue3使用的是html5的新api,Proxy 数据代理
Proxy 是一个构造函数,通过 new Proxy 可以实例化一个代理对象
我们还是先声明一个源对象
let person = {
name: 'ikun',
age: 18
};
然后将传入 new Proxy 的配置参数中
let p = new Proxy(person,{})
如果配置参数中无内容,则默认代理增删改查所有操作,即自动的对以上操作进行监听
配置参数中依然可以有 set 和 get,但是 set 方法可以对增添数据进行代理,但是无法监听到删除,需要使用 deleteProperty 对其代理
let p = new Proxy(person, {
get(target, key) {
},
set(target, key, value) {
},
deleteProperty(target, key) {
}
})
get 和 deleteProperty 方法中传入两个参数,第一个为 target 源对象,第二个是被枚举的属性的键名 key
set 方法中则多以参数,就是 value 修改的新值
所以对代理对象 p 的属性和方法进行修改和枚举的时候,我们可以对其进行一下操作
let p = new Proxy(person, {
// get 传入两个参数,一个是源数据,一个是被读取的键名
get(target, key) {
console.log('p被读取了', a, b);
// 使用 a[b] 既可以获取到对应的键名的值
return a[b]
},
// set 方法接收三个参数,一个是源数据,一个是被被修改的键名,还有一个就是修改的值
// 如果被设置了 set 属性,则不会再通过修改目标数据修改源数据
set(target, key, value) {
// 添加时也同样会调用 Set 方法
console.log('p被修改了', target, key, value);
person[key] = value
},
// 但是删除是无法捕获到的,所以需要使用另一个钩子 deleteProperty
deleteProperty(target, key) {
// deleteProperty 接收两个参数,一个是 target 源数据,一个是 key 被操作的键名
console.log('p中的属性被删除了', target, key);
// deleteProperty 方法存在有一个返回值,删除成功返回的是 true 否则是 false,删除关键字 delete 也有返回值,所以只需要将其返回即可
return delete target[key]
}
})
以上就是 vue2 和 vue3 的响应原理,希望能对您有所帮助