如果又忘了proxy和Reflect就来看这篇文章

292 阅读4分钟

前言

被问到啥是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)