成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

ECMAScript6(12):Proxy 和 Reflect

habren / 3022人閱讀

摘要:返回一個(gè)布爾值攔截操作符,返回一個(gè)布爾值攔截操作符,返回一個(gè)布爾值攔截遍歷器,返回一個(gè)遍歷器攔截,返回一個(gè)布爾值攔截,返回一個(gè)數(shù)組。

Proxy 對(duì)象

Proxy 用來修改某些默認(rèn)操作,等同于在語言層面做出修改。所以屬于一種元編程(meta programming), 即對(duì)編程語言進(jìn)行編程。字面理解為Proxy代理了某些默認(rèn)的操作。
其使用格式如下:

var proxy = new Proxy(target, handler);

target是被代理的目標(biāo)對(duì)象,handler也是個(gè)對(duì)象,用來定制攔截行為,內(nèi)部定義每個(gè)被代理的行為。
注意:

如果希望這個(gè)代理有效,需要在 proxy 對(duì)象上調(diào)用屬性方法,而不是在 target 上調(diào)用

如果指定 handler 為空對(duì)象,那么得到對(duì)象和原對(duì)象一樣

得到的 proxy 是 target 的引用,如果沒有代理,在 proxy 上的修改和在 target 上的修改等同

看一個(gè)簡(jiǎn)單的實(shí)例

var proxy = new Proxy({},{
  get: function(target, key){
    return 35;
  }
});
console.log(proxy.time);    //35
console.log(proxy.name);    //35
console.log(proxy.title);    //35
//被代理的對(duì)象無論輸入什么屬性都返回35

實(shí)際上,proxy 對(duì)象也可以被繼承:

var proxy = new Proxy({},{
  get: function(target, key){
    return 35;
  }
});
var obj = Object.create(proxy);
obj.time = 20;
console.log(obj.time);    //20
console.log(obj.name);    //35

感受一下它的威力:

var obj = new Proxy({}, {
  get: function(target, key, receiver){
    console.log(`getting ${key} ...`);
    return Reflect.get(target, key, receiver);
  },
  set: function(target, key, value, receiver){
    console.log(`setting ${key} ...`);
    return Reflect.set(target, key, value, receiver);
  }
});

obj.count = 1;            //setting count ...
++obj.count;              //getting count ...
                          //setting count ...
console.log(obj.count);   //getting count ...
                          //2

可以看出來,handler對(duì)象中 get 方法表示屬性的訪問請(qǐng)求,set 方法表示屬性的寫入請(qǐng)求。
當(dāng)然不僅僅 get 和 set, 我們可以定義以下攔截函數(shù):

get(target, propKey, receiver = target)

攔截對(duì)象的讀取屬性。當(dāng) target 對(duì)象設(shè)置了 propKey 屬性的 get 函數(shù)時(shí),receiver 綁定 get 函數(shù)的 this。返回值任意

set(target, propKey, value, receiver = target)

攔截對(duì)象的寫入屬性。返回一個(gè)布爾值

has(target, propKey)

攔截 propKey in proxy 操作符,返回一個(gè)布爾值

deleteProperty(target, propKey)

攔截 delete proxy[propKey] 操作符,返回一個(gè)布爾值

enumerate(target)

攔截 for(let i in proxy) 遍歷器,返回一個(gè)遍歷器

hasOwn(target, propKey)

攔截 proxy.hasOwnProperty("foo"),返回一個(gè)布爾值

ownKeys(target)

攔截 Object.getOwnPropertyNames(proxy), Object.getOwnPropertySymbols(proxy), Object.keys(proxy),返回一個(gè)數(shù)組。該方法返回對(duì)象所有自身屬性,包括不可遍歷屬性,不包括 Symble屬性,但是Object.keys(proxy)不應(yīng)該包括不可遍歷屬性

getOwnPropertyDescriptor(target, propKey)

攔截 Object.getOwnPropertyDescriptor(proxy, propKey),返回其屬性描述符

defineProperty(target, propKey, propDesc)

攔截 Object.defineProperty(proxy, propKey, propDesc), Object.defineProperties(proxy, propDesc),返回一個(gè)布爾值

preventExtensions(target)

攔截 Object.preventExtensions(proxy),返回一個(gè)布爾值

getPrototypeOf(target)

攔截 Object.getPrototypeOf(proxy),返回一個(gè)對(duì)象

isExtensible(target)

攔截 Object.isExtensible(proxy),返回一個(gè)布爾值

setPrototypeOf(target, proto)

攔截 Object.setPrototypeOf(proxy, proto),返回一個(gè)布爾值

apply(target, object, args)

攔截對(duì) proxy 實(shí)例的函數(shù)操作,包括 proxy(...args),proxy.call(object, ...args),proxy.apply(object, args)

construct(target, args, proxy)

攔截用 new 調(diào)用 proxy 函數(shù)的操作,construct()返回的不是對(duì)象會(huì)報(bào)錯(cuò)

以下列舉一些 Proxy 的實(shí)例

訪問對(duì)象不存在的屬性報(bào)錯(cuò)

var obj = new Proxy({}, {
  get: function(target, key){
    if(key in target){
      return Reflect.get(target, key);
    } else {
      throw new ReferenceError(`"${key}" is not in object`);
    }
  }
});
obj.look = "picture";
console.log(obj.look);     //"picture"
console.log(obj.sleep);    //ReferenceError: "sleep" is not in object

數(shù)組索引為負(fù)時(shí)返回倒數(shù)位置的值

var origin = [10,20];
var arr = new Proxy(origin, {
  get(target, key){
    let index = parseInt(key);
    if(index < 0){
      index = target.length + index;
      if(index < 0) return undefined;
    }
    return Reflect.get(target, index);
  }
});
console.log(arr[0]);     //10
console.log(arr[1]);     //20
console.log(arr[2]);     //undefined
console.log(arr[-1]);    //20
console.log(arr[-4]);    //undefined

保護(hù)對(duì)象內(nèi)以 "_" 開頭的屬性為私有屬性:

var o = {
  "_name": "Bob",
  "age": 13,
  "_fun": function(){
    console.log("_fun is called");
  }
};
var obj = new Proxy(o, {
  get(target, key){
    if(key.charAt(0) === "_"){
      return undefined;
    }
    return Reflect.get(target, key);
  },
  set(target, key, value){
    if(key.charAt(0) === "_"){
      throw new Error("Cannot define a property begin with "_"");
    }
    return  Reflect.set(target, key, value);
  },
  has(target,key){
    if(key.charAt(0) === "_"){
      return false;
    }
    return Reflect.has(target, key);
  },
  deleteProperty(target,key){
    if(key.charAt(0) === "_"){
      return false;
    } else {
      Reflect.deleteProperty(..arguments);
    }
  },
  apply(target,ctx,args){
    if(target.name.charAt(0) === "_"){
      throw new TypeError(`${target.name} is not defined`);
    } else {
      Reflect apply(...arguments);
    }
  },
  defineProperty(target,key,desc){
    if(key.charAt(0) === "_"){
      return new Error(`cannot define property begin with "_"`);
    } else {
      Reflect.defineProperty(..arguments);
    }
  },
  setPrototypeOf(target,proto){
    throw new TypeError(`Cannot change the proto of ${target}`);
  },
  construct(target,ctx,args){
    if(target.name.charAt(0) === "_"){
      throw new TypeError(`${target.name} is not defined`);
    } else {
      Reflect construct(...arguments);
    }
  }
});

console.log(obj.age);    //13
obj.age = 20;
console.log(obj.age);    //20
console.log(obj._name);  //undefined
obj._hobby = "Coding";   //Error: Cannot define a property begin with "_"
_name in key             //false
delete obj._name;
Object.defineProperty(obj,"_hobby",{
  value: "Coding"
});
Object.defineProperties(obj,{
  "_hobby": {
    value: "Coding"
  }
});
obj._fun();
var a = new obj._fun();
obj.__proto__ = {};     //Cannot define a property begin with "_"
Object.setPrototypeOf(obj,{})    //Cannot change the proto of obj

當(dāng)然不是所有 proxy 代理都不可取消,下面方法設(shè)置的代理是可以通過定義代理時(shí)返回的revoke函數(shù)取消:

var a = {
  name:"Bob"
};
var {proxy, revoke} = Proxy.revocable(a, {
  get(target,key){
    return undefined;
  }
});
proxy.name;   //undefined;
revoke();
proxy.name;   //TypeError: Cannot perform "get" on a proxy that has been revoked
Reflect 對(duì)象

Reflect 對(duì)象有一下作用:

將 Object對(duì)象的一些明顯屬于語言層面的方法部署在 Reflect 上

修改某些 Object 對(duì)象的方法使其更合理。比如 Object.defineProperty 遇到無法定義屬性時(shí)會(huì)拋出錯(cuò)誤,而 Reflect.defineProperty 會(huì)返回 false

把所以 object 的操作都替換成函數(shù)行為,比如用 Reflect.has(obj,name) 替換 name in obj

保證只要是 Proxy 有的方法就一定可以在 Reflect 上找到相同的方法,這樣可以在實(shí)現(xiàn) proxy 時(shí)方便的完成默認(rèn)行為。換言之,無論 proxy 怎么修改默認(rèn)行為,你總可以在 Reflect 上找到真正默認(rèn)的行為

代理在添加額外的功能時(shí),利用 Reflect 保證了原始功能的實(shí)現(xiàn)。舉個(gè)例子:

var loggedObj = new Proxy({}, {
  get(target,propKey){
    console.log(`getting ${target}.${propKey}`);  //當(dāng)然你最好把操作記錄到一個(gè) log 中
    return Reflect.get(target,propKey);
  }
});

Reflect有以下方法:

Reflect.getOwnPropertyDescriptor(target, propKey)

等同于 ObjectgetOwnPropertyDescriptor(target, propKey)

Reflect.defineProperty(target,propKey,desc)

等同于 Object.defineProperty(target,propKey,desc)

Reflect.getOwnPropertyNames(target)

等同于 Object.getOwnPropertyNames(target)

Reflect.getPrototypeOf(target)

等同于 Object.getPrototypeOf(target)

Reflect.setPrototypeOf(target, proto)

等同于 Object.setPrototypeOf(target, proto)

Reflect.deleteProperty(target, propKey)

等同于 delete target.propKey

Reflect.enumerate(target)

等同于 for ... in target

Reflect.freeze(target)

等同于 Object.freeze(target)

Reflect.seal(target)

等同于 Object.seal(target)

Reflect.preventExtensions(target)

等同于 Object.preventExtensions(target)

Reflect.isFrozen(target)

等同于 Object.isFrozen(target)

Reflect.isSealed(target)

等同于 Object.isSealed(target)

Reflect.isExtensible(target)

等同于 Object.isExtensible(target)

Reflect.has(target, propKey)

等同于 propkey in object

Reflect.hasOwn(target, propKey)

等同于 target.hasOwnProperty(propKey)

Reflect.ownKeys(target)

遍歷得到target自身所有屬性,包括不可枚舉屬性,不包括 Symbol 屬性

Reflect.get(target,propKey, receiver = target)

如果 propKey 是個(gè)讀取器,則讀取器中的 this 綁定到 receiver

var per = {
  bar: function(){console.log("per-bar")}
}
var obj = {
  get foo(){ this.bar(); },
  bar: function (){console.log("obj-bar")}
};
Reflect.get(obj, "foo", per);    //"per-bar"

Reflect.set(target,propKey, value, receiver = target)

如果 propKey 是個(gè)讀取器,則讀取器中的 this 綁定到 receiver

Reflect.apply(target, thisArg, args)

等同于 Function.prototype.apply.call(target, thisArg, args)thisArg.target(args)

Reflect.construct(target,args)

等同于 new target(...args)

注意以上方法中,Reflect.set(), Reflect.defineProperty(), Reflect.freeze(), Reflect.seal(), Reflect.preventExtensions() 在成功時(shí)返回 true, 失敗時(shí)返回 false。對(duì)應(yīng)的 Object 方法失敗時(shí)會(huì)拋出錯(cuò)誤。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/97445.html

相關(guān)文章

  • ECMAScript6

    摘要:返回布爾值標(biāo)簽?zāi)0蹇梢跃o跟一個(gè)函數(shù)名后邊,該函數(shù)將被調(diào)用來處理這個(gè)模板字符串。其它情況下返回值為在內(nèi)部,整數(shù)和浮點(diǎn)數(shù)使用同樣的存儲(chǔ)方法,所以和被視為同一個(gè)值。 簡(jiǎn)介 ES6目標(biāo),讓JavaScript變成一個(gè)企業(yè)級(jí)的開發(fā)語言,不僅僅限制與前端頁面的腳本語言。 標(biāo)準(zhǔn)(Standard): 用于定義與其他事物區(qū)別的一套規(guī)則 實(shí)現(xiàn)(Implementation): 某個(gè)標(biāo)準(zhǔn)的具體實(shí)施/真實(shí)實(shí)...

    MSchumi 評(píng)論0 收藏0
  • ECMAScript6(10):Symbol基本類型

    摘要:基本類型是一種解決命名沖突的工具。這樣,就有了個(gè)基本類型和個(gè)復(fù)雜類型使用需要注意以下幾點(diǎn)和一樣不具有構(gòu)造函數(shù),不能用調(diào)用。判斷對(duì)象是否某個(gè)構(gòu)造函數(shù)的實(shí)例,運(yùn)算符會(huì)調(diào)用它是一個(gè)數(shù)組對(duì)象屬性。即,當(dāng)存在時(shí),以此為構(gòu)造函數(shù)構(gòu)建對(duì)象。 Symbol基本類型 Symbol 是一種解決命名沖突的工具。試想我們以前定義一個(gè)對(duì)象方法的時(shí)候總是要檢查是否已存在同名變量: if(String && Str...

    lavor 評(píng)論0 收藏0
  • 《深入理解ES6》筆記——代理(Proxy反射(Reflection)API(12

    摘要:方法與代理處理程序的方法相同。使用給目標(biāo)函數(shù)傳入指定的參數(shù)。當(dāng)然,不用反射也可以讀取的值。的例子我們可以理解成是攔截了方法,然后傳入?yún)?shù),將返回值賦值給,這樣我們就能在需要讀取這個(gè)返回值的時(shí)候調(diào)用。這種代理模式和的代理有異曲同工之妙。 反射 Reflect 當(dāng)你見到一個(gè)新的API,不明白的時(shí)候,就在瀏覽器打印出來看看它的樣子。 showImg(https://segmentfault....

    ZHAO_ 評(píng)論0 收藏0
  • 《深入理解ES6》筆記——代理(Proxy反射(Reflection)API(12

    摘要:方法與代理處理程序的方法相同。使用給目標(biāo)函數(shù)傳入指定的參數(shù)。當(dāng)然,不用反射也可以讀取的值。的例子我們可以理解成是攔截了方法,然后傳入?yún)?shù),將返回值賦值給,這樣我們就能在需要讀取這個(gè)返回值的時(shí)候調(diào)用。這種代理模式和的代理有異曲同工之妙。 反射 Reflect 當(dāng)你見到一個(gè)新的API,不明白的時(shí)候,就在瀏覽器打印出來看看它的樣子。 showImg(https://segmentfault....

    shiina 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<