Proxy与Reflect

Proxy

Proxy可以理解成,在目标对象之前架一层‘拦截’,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy这个词的原意是代理,用在这里表示由它来‘代理’某些操作,可以译为“代理器”

    var proxy = new Proxy(target,handler);

Proxy对象的所有用法,都是上面这种形式,不同的只是handler参数的写法,其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为

  • 举一个拦截器读取属性行为的🌰

      var proxy = new Proxy({}, {
          //get方法的两个参数:目标对象、索要访问的属性
          //可以看到,拦截函数总是返回100,所以任何属性都得到35
          get: function(target, property) {
              return 100;
          }
      })
    
      console.log(proxy.name); // 100
      console.log(proxy.time); // 100
      console.log(proxy.age); // 100
    

注意:要使得Proxy起作用,必须针对Proxy实例进行操作,而不是针对目标对象进行操作
如果handler没有设置任何拦截,那就等同于直接通向原对象

一个技巧是将Proxy对象,设置到object.proxy属性,从而可以在object对象上调用
var object = { proxy: new Proxy(target, handler) }

  • Proxy实例也可以作为其他对象的原型对象

      var proxy = new Proxy({}, {
          get: function(target, property) {
              return 100;
          }
      })
    
      let obj = Object.create(proxy);
      console.log(obj.title);//100
    

上面代码中,proxy对象是obj对象的原型,obj对象本身并没有time属性,所以根据原型链,会在proxy对象上读取该属性,导致被拦截

同一个拦截器,可以设置多个拦截操作,如果对于可以设置,但是没有设置拦截的操作,则直接落在目标对象上,按照原先的方法产生结果

Proxy支持的拦截操作一共是13中:

  • 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),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
  • apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
  • construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。

Reflect

Reflect对象与Proxy对象一样,也是ES6为了操作对象而提供的新的API。Reflect对象的设计目的有这样几个。

  • 将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新的方法将部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法

  • 修改某些Object方法的返回解构,让其变得更合理,比如Object.defineProperty(obj,name,desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj,name,desc)则会返回false

      //老写法
    
      try {
          Object.defineProperty(target, property, attributes)
          //success
      } catch (e) {
          //failure
      }
    
      //新写法
    
      if(Reflect.defineProperty(target, property, attributes)){
          //success
      }else{
          //failure
      }
    
  • 让Object操作都变成函数行为,某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj,name)和Reflect.deleteProperty(obj,name)让他们变成了函数行为

      //老写法
      'name' in obj
    
      //新写法
      Reflect.has(obj,'name')
    
  • Reflect对象的方法与Proxy对象的方法一一对应。只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法,这就让Proxy对象可以方便的调用对应的Reflect方法,完成默认行为,作为修改行为的基础,也就是说,不管Proxy怎么修改默认行为,总可以在Reflect上获取默认行为

      Proxy(target, {
          //Proxy方法拦截target对象的属性赋值行为。
          //它采用Reflect.set方法将值赋值给对象的属性,确保完成原有的行为,然后再部署额外的功能。
          set: function(target, name, value, receiver) {
          var success = Reflect.set(target,name, value, receiver);
          if (success) {
              console.log('property ' + name + ' on ' + target + ' set to ' + value);
          }
          return success;
          }
      });
    

有了Reflect对象之后,很多操作会更易读

    // 老写法
    Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1

    // 新写法
    Reflect.apply(Math.floor, undefined, [1.75]) // 1

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)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容

  • Proxy 对象 Proxy 用来修改某些默认操作,等同于在语言层面做出修改。所以属于一种元编程(meta pro...
    faremax阅读 359评论 0 0
  • 很有意思的一章 Proxy get 利用Proxy,可以将读取属性的操作(get),转变为执行某个函数,从而实现属...
    KeithFu阅读 644评论 0 0
  • defineProperty() 学习书籍《ECMAScript 6 入门 》 Proxy Proxy 用于修改某...
    Bui_vlee阅读 654评论 0 1
  • 下班回来锻炼 跳小红帽 大概15分钟。家里地方太小,客厅跳婆婆坐在我面前实在跳不下去。算了 晚饭吃了6 7分饱。 ...
    越流阅读 49评论 0 0
  • 很慌乱怕一个不小心就慢了一步。很恐惧怕走错了一步就不再成为喜欢的自己。绵密的惶恐开始让我咄咄不安,惶惶不可终日。恐...
    五花球球阅读 573评论 0 1