es6 新特性 之 Proxy, 这次彻底搞懂
es6提供了一些新特性,其中就有Proxy构造函数,用来生成Proxy实例的,它是一种拦截器。可以理解成,在目标对象之前假设一层”拦截“,外界对该对象饿访问,都必须先通过这层拦截。
因此提供了一种机制,可以对外界的访问进行过滤和改写。
what 是什么
proxy对象 用于 创建一个对象的 代理
,从而实现基本操作的 拦截
和自定义 (比如:属性查找
、赋值
、枚举
、函数调用
等)。
how 怎么样用
const p = new Proxy(target, handler)
-
target: 要使用proxy包装的
目标对象
(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。 -
handler: 一个通常以
函数作为属性
的对象
,各属性中的函数分别定义
了在执行各种操作时代理p
的行为
。
其中Proxy的拦截方法共有13种。
-
apply(target, object, args):
拦截
Proxy实例作为函数调用
的操作, 比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...) -
get(target, propKey, receiver):
拦截对象属性的读取
,比如proxy.foo和proxy[‘foo’]。 -
set(target, propKey, value, receiver):
拦截对象属性的设置
,比如proxy.foo = v或proxy[‘foo’] = v,返回一个布尔值。 -
has(target, propKey):
拦截propKey in proxy的操作
,返回一个布尔值。 -
deleteProperty(target, propKey):
拦截delete proxy[propKey]的操作
,返回一个布尔值。 -
ownKeys(target):
拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for…in循环
,返回一个数组。该方法返回目标对象所有自身的属性的属性名
,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。 -
getOwnPropertyDescriptor(target, propKey):
拦截Object.getOwnPropertyDescriptor(proxy, propKey)
,返回属性的描述对象。 -
defineProperty(target, propKey, propDesc):
拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs)
,返回一个布尔值。 -
preventExtensions(target):
拦截Object.preventExtensions(proxy)
,返回一个布尔值。 -
getPrototypeOf(target):
拦截Object.getPrototypeOf(proxy)
,返回一个对象。 -
isExtensible(target):
拦截Object.isExtensible(proxy)
,返回一个布尔值。 -
setPrototypeOf(target, proto):
拦截Object.setPrototypeOf(proxy, proto)
,返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。 -
construct(target, args):
拦截 Proxy 实例作为构造函数调用的操作
,比如new proxy(…args)。
下面着重分析一下apply、get、set这三种。
handler.apply()
handler = {
apply() // 拦截函数的调用
}
语法:
var p = new Proxy(target, {
apply: function(target, thisArg, argumentsList) {
}
});
target: 目标对象(函数)。
thisArg:被调用时的上下文对象。
argumentsList: 被调用时的参数数组。
返回值:apply 方法可以返回任何值。
拦截目标对象:
- proxy(...args)
- Function.prototype.apply() 和 Function.prototype.call()
- Reflect.apply()
示例1:
function sum(a, b) {
return a + b
}
const handler = {
apply: function(target, thisArg, argumentsList) {
console.log('target', target) // sum()这个函数本身
console.log('thisArg', thisArg) // undefined
console.log('argumentsList', argumentsList) // [1, 2]
return target(argumentsList[0], argumentsList[1]) * 10
}
}
const proxy1 = new Proxy(sum, handler)
console.log(sum(1, 2)) // expected output: 3
console.log(proxy1(1, 2)) // expected output: 30
示例2:
var p = new Proxy(function() {}, {
apply: function(target, thisArg, argumentsList) {
console.log('called: ' + argumentsList.join(', ')) // called: 1, 2, 3
return argumentsList[0] + argumentsList[1] + argumentsList[2]
}
})
console.log(p(1, 2, 3)) // 6
handler.get()
handler = {
get() // 拦截对象的读取属性操作
}
语法:
var p = new Proxy(target, {
get: function(target, property, receiver) {
}
});
target: 目标对象(函数)。
property:被获取的属性名。
receiver: Proxy或者继承Proxy的对象。
返回值:get方法可以返回任何值。
拦截目标对象:
- 访问属性:proxy[foo] 和 proxy.bar
- 访问原型链上的属性:Object.create(proxy)[foo]
- Reflect.get()
示例1:
var p = new Proxy({}, {
get: function(target, prop, receiver) {
console.log('target', target) // {}
console.log('called: ' + prop) // "called: a“
console.log('receiver', receiver) // Proxy {}
return 10
}
})
console.log(p.a) // 10
示例2:
var obj = {}
Object.defineProperty(obj, 'a', {
configurable: false,
enumerable: false,
value: 10,
writable: false
})
var p = new Proxy(obj, {
get: function(target, prop) {
return 20
}
})
console.log(p.a) // 会抛出 TypeError 'get'上的代理:属性'a'是一个只读的和不可配置的数据属性
handler.set()
handler = {
set() // 拦截对象的设置属性操作
}
语法:
var p = new Proxy(target, {
set: function(target, property, receiver) {
}
});
target: 目标对象(函数)。
property:被设置的属性名。
receiver: Proxy或者继承Proxy的对象。
返回值:set方法应当返回一个布尔值。
- 返回
true
代表属性设置成功。 - 在严格模式下,如果
set()
方法返回false
,那么会抛出一个TypeError
异常。
拦截目标对象:
- 访问属性:proxy[foo] = bar 和 proxy.bar = foo
- 访问原型链上的属性:Object.create(proxy)[foo] = bar
- Reflect.set()
示例1:
const monster1 = { eyeCount: 4 }
const handler1 = {
set(obj, prop, value) {
if ((prop === 'eyeCount') && ((value % 2) !== 0)) {
console.log('Monsters must have an even numbers of eyes')
} else {
return Reflect.set(...arguments)
}
}
}
const proxy1 = new Proxy(monster1, handler1)
proxy1.eyeCount = 1 // expected Output: "Monsters must have an even numbers of eyes"
console.log(proxy1.eyeCount); // expected Output: 4
proxy1.eyeCount = 2
console.log(proxy1.eyeCount) // expected output: 2
转载自:https://juejin.cn/post/7134644264276852772