国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

ECMAScript6(12):Proxy 和 Reflect

habren / 3001人閱讀

摘要:返回一個布爾值攔截操作符,返回一個布爾值攔截操作符,返回一個布爾值攔截遍歷器,返回一個遍歷器攔截,返回一個布爾值攔截,返回一個數組。

Proxy 對象

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

var proxy = new Proxy(target, handler);

target是被代理的目標對象,handler也是個對象,用來定制攔截行為,內部定義每個被代理的行為。
注意:

如果希望這個代理有效,需要在 proxy 對象上調用屬性方法,而不是在 target 上調用

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

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

看一個簡單的實例

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
//被代理的對象無論輸入什么屬性都返回35

實際上,proxy 對象也可以被繼承:

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對象中 get 方法表示屬性的訪問請求,set 方法表示屬性的寫入請求。
當然不僅僅 get 和 set, 我們可以定義以下攔截函數:

get(target, propKey, receiver = target)

攔截對象的讀取屬性。當 target 對象設置了 propKey 屬性的 get 函數時,receiver 綁定 get 函數的 this。返回值任意

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

攔截對象的寫入屬性。返回一個布爾值

has(target, propKey)

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

deleteProperty(target, propKey)

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

enumerate(target)

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

hasOwn(target, propKey)

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

ownKeys(target)

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

getOwnPropertyDescriptor(target, propKey)

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

defineProperty(target, propKey, propDesc)

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

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(object, args)

construct(target, args, proxy)

攔截用 new 調用 proxy 函數的操作,construct()返回的不是對象會報錯

以下列舉一些 Proxy 的實例

訪問對象不存在的屬性報錯

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

數組索引為負時返回倒數位置的值

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

保護對象內以 "_" 開頭的屬性為私有屬性:

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

當然不是所有 proxy 代理都不可取消,下面方法設置的代理是可以通過定義代理時返回的revoke函數取消:

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 對象

Reflect 對象有一下作用:

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

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

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

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

代理在添加額外的功能時,利用 Reflect 保證了原始功能的實現。舉個例子:

var loggedObj = new Proxy({}, {
  get(target,propKey){
    console.log(`getting ${target}.${propKey}`);  //當然你最好把操作記錄到一個 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 是個讀取器,則讀取器中的 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 是個讀取器,則讀取器中的 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() 在成功時返回 true, 失敗時返回 false。對應的 Object 方法失敗時會拋出錯誤。

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

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/97445.html

相關文章

  • ECMAScript6

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

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

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

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

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

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

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

    shiina 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<