持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第32天,点击查看活动详情
Object.defineProperty
的存储属性描述符来对 属性的操作进行监听。 ```js const obj = { name: "why", age: 18 }
Object.defineProperty(obj, "name", { get: function() { console.log("监听到obj对象的name属性被访问了") }, set: function() { console.log("监听到obj对象的name属性被设置值") } })
* **但是这样做有什么缺点呢?**
* 首先,Object.defineProperty设计的初衷,不是为了去监听截止一个对象中所有的属性的。
* 我们在定义某些属性的时候,初衷其实是定义普通的属性,但是后面我们强 行将它变成了数据属性描述符。
* 其次,如果我们想监听更加丰富的操作,比如新增属性、删除属性,那么 Object.defineProperty是无能为力的。
* 所以我们要知道,存储数据描述符设计的初衷并不是为了去监听一个完整的对象。
# Proxy基本使用
* 在ES6中,新增了一个[Proxy类](url),这个类从名字就可以看出来,是用于帮助我们创建一个**代理**的:
* 也就是说,如果我们希望`监听一个对象的相关操作`,那么我们可以`先创建一个代理对象(Proxy对象)`;
* 之后对`该对象的所有操作`,都通过`代理对象来完成`,代理对象`可以监听我们想要对原对象进行哪些操作`;
* 我们可以将上面的案例用Proxy来实现一次:
* 首先,我们需要new Proxy对象,并且传入需要侦听的对象以及一个处理对象,可以称之为handler;
* const p = new Proxy(target, handler)
* 其次,我们之后的操作都是直接对Proxy的操作,而不是原有的对象,因为我们需要在handler里面进行侦听;
## Proxy的set和get捕获器
* 如果我们想要侦听某些具体的操作,那么就可以在handler中添加对应的捕捉器(Trap):
* set和get分别对应的是函数类型;
* set函数有四个参数:
* target:目标对象(侦听的对象);
* property:将被设置的属性key;
* value:新属性值;
* receiver:调用的代理对象;
* get函数有三个参数:
* target:目标对象(侦听的对象);
* property:被获取的属性key;
* receiver:调用的代理对象;
### 代码展示
```js
const obj = {
name: "why",
age: 18
}
const objProxy = new Proxy(obj, {
// 获取值时的捕获器
get: function(target, key) {
console.log(`监听到对象的${key}属性被访问了`, target)
return target[key]
},
// 设置值时的捕获器
set: function(target, key, newValue) {
console.log(`监听到对象的${key}属性被设置值`, target)
target[key] = newValue
}
})
handler.setPrototypeOf() Object.setPrototypeOf 方法的捕捉器。
handler.isExtensible() Object.isExtensible 方法的捕捉器。
handler.preventExtensions() Object.preventExtensions 方法的捕捉器。
handler.getOwnPropertyDescriptor() Object.getOwnPropertyDescriptor 方法的捕捉器。
handler.defineProperty() Object.defineProperty 方法的捕捉器。
handler.ownKeys() Object.getOwnPropertyNames 方法和Object.getOwnPropertySymbols 方法的捕捉器。
handler.has() in 操作符的捕捉器。
handler.get() 属性读取操作的捕捉器。
handler.set() 属性设置操作的捕捉器。
handler.deleteProperty() delete 操作符的捕捉器。
handler.apply() 函数调用操作的捕捉器。
handler.construct() new 操作符的捕捉器。
## Proxy的construct和apply
当然,我们还会看到捕捉器中还有construct和apply,它们是应用于函数对象的:
```js
function foo() {
}
const fooProxy = new Proxy(foo, {
apply: function(target, thisArg, argArray) {
console.log("对foo函数进行了apply调用")
return target.apply(thisArg, argArray)
},
construct: function(target, argArray, newTarget) {
console.log("对foo函数进行了new调用")
return new target(...argArray)
}
})
fooProxy.apply({}, ["abc", "cba"])
new fooProxy("abc", "cba")
操作JavaScript对象的方法
,有点像Object中操作对象的方法
;如何设计会更加规范,所以将这些API放到了Object上面
; Object作为一个构造函数
,这些操作实际上放到它身上并不合适
;类似于 in、delete操作符
,让JS看起来是会有一些奇怪的;新增了Reflect
,让我们这些操作都集中到了Reflect对象上;Reflect中有哪些常见的方法呢?它和Proxy是一一对应的,也是13个:
Reflect.getPrototypeOf(target)
类似于 Object.getPrototypeOf()
Reflect.setPrototypeOf(target, prototype)
设置对象原型的函数. 返回一个 Boolean, 如果更新成功,则返 回true。
Reflect.isExtensible(target)
类似于 Object.isExtensible()
Reflect.preventExtensions(target)
类似于 Object.preventExtensions()。返回一个Boolean。
Reflect.getOwnPropertyDescriptor(target, propertyKey)
类似于 Object.getOwnPropertyDescriptor()。如果对象中存在该属性,则返回对应的属性描述符, 否则返回 undefined.
Reflect.defineProperty(target, propertyKey, attributes)
和 Object.defineProperty() 类似。如果设置成功就会返回 true
Reflect.ownKeys(target)
返回一个包含所有自身属性(不包含继承属性)的数组。(类似于Object.keys(), 但不会受enumerable影响).
Reflect.has(target, propertyKey)
判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。
Reflect.get(target, propertyKey[, receiver])
获取对象身上某个属性的值,类似于 target[name]。
Reflect.set(target, propertyKey, value[, receiver])
将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true。
Reflect.deleteProperty(target, propertyKey)
作为函数的delete操作符,相当于执行 delete target[name]。
Reflect.apply(target, thisArgument, argumentsList)
对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似。
Reflect.construct(target, argumentsList[, newTarget])
对构造函数进行 new 操作,相当于执行 new target(...args)。
那么我们可以将之前Proxy案例中对原对象的操作,都修改为Reflect来操作:
const obj = {
name: "why",
age: 18
}
const objProxy = new Proxy(obj, {
get: function(target, key, receiver) {
console.log("get---------")
return Reflect.get(target, key)
},
set: function(target, key, newValue, receiver) {
console.log("set---------")
target[key] = newValue
const result = Reflect.set(target, key, newValue)
if (result) {
} else {
}
}
})
objProxy.name = "kobe"
console.log(objProxy.name)