前言
被问到啥是proxy和reflect是什么的时候,完全不知道是啥,感觉基础还是差好多。所以需要来记录下学习之后对于proxy和reflect的理解。用我自己的话概述下。
Proxy
啥是 proxy?proxy在英文里为代理人的意思,顾名思义,就是通过proxy可以架设一个一层代理层,也就是一层拦截。当外界要对某个设了拦截的对象访问,访问的就是这层代理里面的内容。通过proxy,我们可以对某些对象进行过滤或者修改。 从官方的文档的解释里我们可以看到:Proxy⽤于修改某些操作的默认⾏为, 等同于在语⾔层⾯做出修改, 所以属于 ⼀种“元编程”( meta programming) , 即对编程语⾔进⾏编程。
proxy支持的拦截操作一览
1. get(target, propKey, receiver) 拦截对象属性的读取, ⽐如 proxy.foo 和 proxy['foo'] ,最后⼀个参数 receiver 是⼀个对象, 可选,其实就是当propKey部署了读取函数,则读取函数的this,绑定receiver。
var obj = {
get foo() { return this.bar(); },
bar: function() { ... }
};
// 下⾯语句会让 this.bar()
// 变成调⽤ wrapper.bar()
Reflect.get(obj, "foo", wrapper);
2. set(target, propKey, value, receiver) 拦截对象属性的设置, ⽐如 proxy.foo = v 或 proxy['foo'] = v , 返回⼀个布尔值。
3. has(target, propKey) 拦截 propKey in proxy 的操作, 以及对象的 hasOwnProperty ⽅法, 返回⼀个布尔值。
4. deleteProperty(target, propKey) 拦截 delete proxy[propKey] 的操作, 返回⼀个布尔值。
5. ownKeys(target) 拦 截Object.getOwnPropertyNames(proxy) 、 Object.getOwnPropertySymbols(proxy) 、Object.keys(proxy) , 返回⼀个数组。 该⽅法返回对象所有⾃身的属性, ⽽ Object.keys() 仅返回对象可遍历的属性。
6. getOwnPropertyDescriptor(target, propKey) 拦截 Object.getOwnPropertyDescriptor(proxy, propKey) , 返回属性的描述对象。
7. defineProperty(target, propKey, propDesc) 拦截 Object.defineProperty(proxy, propKey,propDesc) 、 Object.defineProperties(proxy, propDescs) , 返回⼀个布尔值。
8. preventExtensions(target) 拦截 Object.preventExtensions(proxy) , 返回⼀个布尔值。
9. getPrototypeOf(target) 拦截 Object.getPrototypeOf(proxy) , 返回⼀个对象。
10. isExtensible(target) 拦截 Object.isExtensible(proxy) , 返回⼀个布尔值。
11. setPrototypeOf(target, proto) 拦截 Object.setPrototypeOf(proxy, proto) , 返回⼀个布尔值。
12. construct(target, args) 拦截Proxy实例作为构造函数调⽤的操作, ⽐如 new proxy(...args)
如果拦截对象是函数,那么还有两种额外操作可以拦截
13. apply(target, object, args) 拦截Proxy实例作为函数调⽤的操作, ⽐如 proxy(...args) 、 proxy.call(object, ...args) 、 proxy.apply(...) 做道题理解下,看看输出啥
var handler = {
get: function (target, name) {
if (name === 'prototype') {
return Object.prototype;
}
return 'Hello, ' + name;
},
apply: function (target, thisBinding, args) {
return args[0];
},
construct: function (target, args) {
return {value: args[1]};
}
};
var fproxy = new Proxy(function (x, y) {
return x + y;
}, handler);
console.log(fproxy(1, 2)); // 直接调用的话,相当于apply的拦截
console.log(new fproxy(1, 2)); // new 了实例的话 就是construct的拦截
console.log(fproxy.prototype === Object.prototype); // 调用属性,相当于get
console.log(fproxy.foo); // 调用属性,相当于get
Reflect
啥是 Reflect? 我的理解是reflect 可以对标 Object,是可以操作对象的API。 reflect设计的目的是以下几点
1.ES6将Object 对象的⼀些明显属于语⾔内部的⽅法( ⽐如 Object.defineProperty ),放到 Reflect 对象上。
2.修改某些Object⽅法的返回结果, 让其变得更合理。⽐如, Object.defineProperty(obj, name, desc) 在⽆法定义属性时, 会抛出⼀个错误, ⽽ Reflect.defineProperty(obj, name, desc) 则会返回 false 。
3.让 Object 操作都变成函数⾏为。某些 Object 操作是命令式, ⽐如 name in obj 和 delete obj[name] , ⽽ Reflect.has(obj,name) 和 Reflect.deleteProperty(obj, name) 让它们变成了函数⾏为。
4.Reflect 对象的⽅法与 Proxy 对象的⽅法⼀⼀对应, 只要是 Proxy 对象的⽅法, 就能在 Reflect 对象上找到对应的⽅法。 这就 让 Proxy 对象可以⽅便地调⽤对应的 Reflect ⽅法, 完成默认⾏为, 作为修改⾏为的基础。
Proxy(target, {
set: function(target, name, value, receiver) {
var success = Reflect.set(target, name, value, receiver);
if (success) {
log('property ' + name + ' on ' + target + ' set to ' +
value);
} r
eturn success;
}
});
5.Reflect 对象的⽅法清单如下, 共13个,这些方法大部分与Object 对象的同名⽅法的作⽤都是相同 的, ⽽且它与 Proxy 对象的⽅法是⼀⼀对应的
- Reflect.apply(target,thisArg,args)
- Reflect.construct(target,args)
- Reflect.get(target,name,receiver)
- Reflect.set(target,name,value,receiver)
- Reflect.defineProperty(target,name,desc)
- Reflect.deleteProperty(target,name)
- Reflect.has(target,name)
- Reflect.ownKeys(target)
- Reflect.isExtensible(target)
- Reflect.preventExtensions(target)
- Reflect.getOwnPropertyDescriptor(target, name)
- Reflect.getPrototypeOf(target)
- Reflect.setPrototypeOf(target, prototype)