前言
Vue2实现数据双向绑定监听的核心如下:
// 监听所有的属性: 遍历所有的属性, 对每一个属性使用defineProperty
const keys = Object.keys(obj)
for (const key of keys) {
let value = obj[key]
Object.defineProperty(obj, key, {
set: function(newValue) {
console.log(`监听: 给${key}设置了新的值:`, newValue)
value = newValue
},
get: function() {
console.log(`监听: 获取${key}的值`)
return value
}
})
}
- 缺点:
①Object.defineProperty设计的初衷,不是为了去监听截止一个对象中所有的属性的。我们在定义某些属性的时候,初衷其实是定义普通的属性,但是后面我们强行将它变成了数据属性描述符。
②如果我们想监听更加丰富的操作,比如新增属性、删除属性,那么Object.defineProperty是无能为力的。
在ES6中,新增了一个Proxy类,用于代理。如果我们希望监听一个对象的相关操作,那么我们可以先创建一个代理对象(Proxy对象)之后对该对象的所有操作,都通过代理对象来完成,代理对象可以监听我们想要对原对象进行哪些操作;
- Vue3就是基于Proxy来实现的 这是与Vue2最大的区别 为什么快了?因为节约了性能不需要有那么多遍历的耗时操作了!
Proxy的set和get捕获器
Proxy当中所有捕获器
仔细看你会发现,返回大多都为boolean,这样就可以过滤掉更多刁钻情况。
举个栗子:
"use strict"
const obj = {
name: "why",
age: 18
}
Object.defineProperty(obj, "name", {
configurable: false
})
// Reflect.defineProperty()
// 1.用以前的方式进行操作
// delete obj.name
// if (obj.name) {
// console.log("name没有删除成功")
// } else {
// console.log("name删除成功")
// }
// 2.Reflect
if (Reflect.deleteProperty(obj, "name")) {
console.log("name删除成功")
} else {
console.log("name没有删除成功")
}
Proxy的construct和apply
Reflect反射
reflect作用:
- 它主要提供了很多操作JavaScript对象的方法,有点像Object中操作对象的方法;
- 比如Reflect.getPrototypeOf(target)类似于 Object.getPrototypeOf();
- 比如Reflect.defineProperty(target, propertyKey, attributes)类似于Object.defineProperty() ;
疑问?
如果我们有Object可以做这些操作,那么为什么还需要有Reflect这样的新增对象呢?
- 这是因为在早期的ECMA规范中没有考虑到这种对 对象本身 的操作如何设计会更加规范,所以将这些API放到了Object上面;
- 但是Object作为一个构造函数,这些操作实际上放到它身上并不合适;
- 另外还包含一些类似于 in、delete操作符,让JS看起来是会有一些奇怪的;
- 所以在ES6中新增了Reflect,让我们这些操作都集中到了Reflect对象上;
- 另外在使用Proxy时,可以做到不操作原对象;