Vue2.x 实现响应式
Vue响应式原理?为什么data数据改变页面也会发生变化?
数据劫持与观察者模式是实现响应式,核心API Object.defineProperty()
Object.definedProperty()可以做数据劫持和数据代理,从而实现Vue响应式
<script>
// 将对象类型的数据变成响应式的数据,需要进行深度监听
const data = {
name: "zhangsan",
age: 12,
friends: {
name: "lisi",
age: 20
},
arr1: ["aaa", 'bbb', 111]
}
// 对于响应式的数据不能直接删除或者添加一个数据
// 需要借助vue.set 和 vue.delete
// vue2对数组的原型上的方法进行了二次封装,可以让数组的一些方法实现响应式
const oldArrayProto = Array.prototype
const newArrayProto = Object.create(oldArrayProto) //newArratProto对象的原型上添加上数组的原型上的方法
// console.log(newArratProto);
const arrMethod = ["pop", 'push', 'unshift', 'splice', 'indexOf', 'includes']
arrMethod.forEach(item => {
newArrayProto[item] = function () {
oldArrayProto[item].call(this, ...arguments) //调用数组的原型上的方法
}
})
observer(data) //可以将data的数据变成响应式的
// 观察者模式:观察值是否是引用类型的数据
function observer(value) {
if (!(value instanceof Object) || value === null) {
return value
}
if (value instanceof Array) {
value.__proto__ = newArrayProto
}
for (let key in value) {
defineReactive(value, key, value[key])
}
}
// 数据劫持
function defineReactive(obj, key, val) {
observer(val)
Object.defineProperty(obj, key, {
get() {
return val1
},
set(newVal) {
observer(val)
console.log("xxx");
if (newVal !== val) {
val = newVal
console.log(newVal, "视图发生更新");
}
}
})
}
// data.name = "hhh"
// data.friends.name = "xxx"
// data.age = { count: 0 }
// data.age.count = 100
// console.log(data.arr1.push("xxx"));
// console.log(data.arr1);
</script>
Vue3.x 实现响应式
vue3底层实现响应式:window.Proxy[代理对象] + window.Reflect.defineProperty() 【反射对象】
<script>
let person = {
name: "zhangsan",
age: 12,
// sex: "男"
}
// 模拟Vue2数据响应式:vue2实现响应式过程比较复杂,而且监听不到对象属性的删除,
/* let sex = "男"
Object.defineProperty(person, "sex", {
get() { // 只能监听对象属性的获取
return sex
},
set(newVal) { //只能监听到对象属性的修改
sex = newVal
}
}) */
// vue3底层实现响应式:window.Proxy[代理对象] + window.Reflect.defineProperty() 【反射对象】
const p = new Proxy(person, {
// get可以监听到属性的获取
//get第一个参数:是当前代理对象p 代理 的源对象【Proxy的第一个参数】; 第二个参数:是当前是使用代理对象访问到的属性名
get(target, propName) {
console.log("读取了p上的属性:", propName);
// return target[propName]
return Reflect.get(target, propName)
},
// set可以监听到属性的变化
// set第一个参数:是当前代理对象p 代理 的源对象【Proxy的第一个参数】; 第二个参数:是当前是使用代理对象访问到的属性名;第三个参数:新的值
set(target, propName, newVal) {
console.log("修改了p上的属性:", propName);
// target[propName] = newVal
Reflect.set(target, propName, newVal)
},
// 监听属性删除:第一个参数:是当前代理对象p 代理 的源对象【Proxy的第一个参数】; 第二个参数:是当前是使用代理对象访问到的属性名;
deleteProperty(target, propName) {
console.log("删除p上的属性:", propName);
// return delete target[propName] //删除成功就返回true 删除失败就返回false
return Reflect.deleteProperty(target, propName)
}
}) // p代理对象可以映射一个对象[对p进行操作,就相当于对对象进行操作,p代理对象可以检测到对代理对象的任何操作]
console.log(p);
</script>