1. 程式人生 > >ES6的代理Proxy和反射Reflect

ES6的代理Proxy和反射Reflect

一、Proxy

Proxy(代理)是 ES6 中新增的一個特性。Proxy 讓我們能夠以簡潔易懂的方式控制外部對物件的訪問。其功能非常類似於設計模式中的代理模式。

使用 Proxy 的好處是:物件只需關注於核心邏輯,一些非核心的邏輯(如:讀取或設定物件的某些屬性前記錄日誌;設定物件的某些屬性值前,需要驗證;某些屬性的訪問控制等)可以讓 Proxy 來做。從而達到關注點分離,降級物件複雜度的目的。
https://www.jianshu.com/p/34f0e6abe312

使用語法:
var p = new Proxy(target, handler);
其中,target 為被代理物件。handler 是一個物件,其聲明瞭代理 target 的一些操作。p 是代理後的物件。
當外界每次對 p 進行操作時,就會執行 handler 物件上的一些方法。
handler 能代理的一些常用的方法如下:


1、get(target,key):讀取
2、set(target,key,value):修改
3、has(target,key):判斷物件是否有該屬性
4、deleteProperty(target,key):刪除某個屬性
5、ownKeys(target):獲取所有的屬性名
6、construct:建構函式
…等等。

代理中把以 _ 開頭的變數都認為是私有的,不能進行讀取和修改。

在這裡插入圖片描述
還有些常用的方法例子和使用方式:
在這裡插入圖片描述在這裡插入圖片描述

二、Reflect

Reflect(反射)是ES6為更方便的操作物件而提供的新API 。

這個API設計的目的只要有:

1.將Object上明顯屬於語言內部的方法放到Reflect上

2.修改某些Object上方法的返回結果,使其變得合理

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怎麼修改預設行為,你總可以在Reflect上獲取預設行為。
在這裡插入圖片描述


Reflect物件一共有13個靜態方法:
Reflect.apply(target,thisArg,args)
Reflect.construct(target,args)
Reflect.get(target,key,receiver)
Reflect.set(target,key,value,receiver)
Reflect.defineProperty(target,key,desc)
Reflect.deleteProperty(target,key)
Reflect.has(target,key)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, key)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)
上面這些方法的作用,大部分與Object物件的同名方法的作用都是相同的,而且它與Proxy物件的方法是一一對應的。

三、Proxy和Reflect的實際使用

對設定資料進行規則驗證:

  // 定義一個校驗函式,返回代理物件
  function validator(target,validator){
    return new Proxy(target,{
      _validator:validator,
      set(target,key,value,proxy){
        if(target.hasOwnProperty(key)){
          let va=this._validator[key];
          // 有這個屬性名並且設定的值符合校驗規則才能設定
          if(!!va(value)){
            return Reflect.set(target,key,value,proxy)
          }else{
            throw Error(`不能設定${key}${value}`)
          }
        }else{
          throw Error(`${key} 不存在`)
        }
      }
    })
  }
  // 校驗規則
  let personValidators={
    name(val){
      return typeof val==='string'
    },
    age(val){
      return typeof val === 'number' && val > 18
    }
  }

  class Person{
    constructor(name,age){
      this.name=name;
      this.age=age;
            // 傳入this類的例項,校驗規則
      return validator(this,personValidators)
    }
  }
  //例項化類Person
  let person=new Person('xf',30);

  console.info(person);

  // person.name=22; //報錯,不讓設定
  person.name='winne';

  console.log(person);

這樣寫的好處:隨時能想驗證規則物件中新增驗證規則,然後在中新增屬性就可以了,用的時候就用,不用的時候也不需要管。方便擴充套件和提高可維護性。