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

資訊專欄INFORMATION COLUMN

ES6之Proxy & Reflection API

yearsj / 1391人閱讀

摘要:的出現,使用內建對象的繼承得以實現。屬性不存在拋出異常是取值操作,而就是賦值操作,可以對屬性值進行驗證。屬性必須為數字拋出異常接受兩個參數被讀取屬性的原對象,即代理的目標。這個可以攔截內部方法,通過返回數組的值可以覆寫其行為。

Proxy & Reflect

extends的出現,使用內建對象的繼承得以實現。Proxy可以攔截JS引擎內部目標的底層對象操作,這些底層操作被攔截后會觸發響應特定操作的陷阱函數(traps),對于別人封裝好的對象或內建對象,都可以自定義操作。
而反射(Reflect)API是以Reflect對象的形式出現的。API中的默認特征與相同的底層操作是一致的,而通過代理可以重寫這些操作,每個代理Trap,對應一個命名和參數值都相同的Reflect方法。
Reflect 中所有方法及說明--MDN

const target = {};
const proxy = new Proxy(target, {});
proxy.title = "proxy";
console.log(proxy.title);
console.log(target.title);

target.title = "target";
console.log(target.title);
console.log(proxy.title);

非常簡單的Proxy,沒有實現任何自定義的Trap 方法,都是默認實現。

GET Trap
let handler = {
    get: function(target, name){
        return name in target ? target[name] : 37;
    }
};

let p = new Proxy({}, handler);

p.a = 1;
p.b = undefined;

console.log(p.a, p.b);    // 1, undefined

console.log("c" in p, p.c);    // false, 37

來自于MDN的一個小例子,語法極其簡單。get trap function 有3個參數:

TrapTarget 被讀取屬性的原對象,即代理的目標。

key 要讀取的屬性(字符串或Symbol)

receiver 發生操作的對象,通常為代理。

而get trap 能做什么用呢?或者說,我們在什么時候使用get呢?一個最主要的功能,驗證對象結構。

對象結構:對象中所有可用的屬性和方法集合。JS引擎通過對象結構來優化代碼,通常會創建類來表示對象。
let proxy = new Proxy({}, {
    get(target, key, receiver) {
        if (!(key in receiver )) {
            throw new TypeError(`屬性 ${key} 不存在`);
        }

        return Reflect.get(target, key, receiver);
    }
});

proxy.name = "proxy";
console.log(proxy.name);  // proxy

console.log(proxy.age);  // 拋出 TypeError 異常
SET Trap

get是取值操作,而set就是賦值操作,可以對屬性值進行驗證。

let target = {
    name: "target"
}

let proxy = new Proxy(target, {
    set(target, key, value, receiver) {
        if (!(key in receiver )) {
            if (isNaN(value)) {
                throw new TypeError("屬性必須為數字");
            }
        }

        return Reflect.set(target, key, value, receiver);
    }
});

proxy.count = 10;
console.log(proxy.count);  // 10
console.log(proxy.count);  // 10

proxy.name = "tom";
console.log(proxy.name);  // tom
console.log(target.name);  // tom

proxy.secondName = "Lee"; // 拋出 TypeError 異常
Has Trap

has trap function 接受兩個參數

TrapTarget 被讀取屬性的原對象,即代理的目標。

key 要讀取的屬性(字符串或Symbol)

可以用來隱藏已有屬性。

// has trap
let target = {
    name: "target",
    age: 24
}

let proxy = new Proxy(target, {
    has(target, key) {
        if (key === "age"){
            return false;
        } else {
            return Reflect.has(target, key);
        }
    }
});

console.log("age" in proxy);  // false
console.log("age" in target);  // true
console.log("name" in proxy);  // true
console.log("name" in target);  // true
deleteProperty Trap

delete操作可以從對象中移除屬性,如果成功則返回true, 失敗返回 false 。在嚴格模式下,刪除一個不可配置屬性,則會拋出錯誤,而在非嚴格模式下,只是返回false.

let target = {
    name: "target",
    age: 24
}

let proxy = new Proxy(target, {
    deleteProperty(target, key) {
        if (key === "age"){
            return false;
        } else {
            return Reflect.deleteProperty(target, key);
        }
    }
});

console.log( "age" in proxy);

const r1 = delete proxy.age;

console.log(r1);

console.log( "name" in proxy);

const r2 = delete proxy.name;

console.log(r2);
原型 Trap

這個要了解一點:Object.get/setPrototypeOf 與 Reflect.get/setPrototypeOf 的區別。
從功能上來講,兩個操作是一致的。但從實現上來講,Object.get/setPrototypeOf 是高級方法,創建伊始就給開發者使用,而Reflect.get/setPrototypeOf 是更底層的操作,使開發者可以訪問之前只在內部操作的[[Get/SetPrototypeOf]]。
面對兩套方法選擇時,可能會讓人無所適從,不知道選哪個更好。有一點可以確認的是,Object提供的方法更高級,是對Reflect方法的包裹器,最終還是會調用Reflect方法,但在此之前,會執行一些額外的步驟,并通過檢查返回值,來確定下一步怎么操作。

可擴展 Trap

對象可擴展,Object.isExtensible和Object.preventExtesions 方法,在ES5下已經實現,而ES6中通過 Reflect.isExtensible和Reflect.preventExtensions來實現。

var p = new Proxy({}, {
  isExtensible: function(target) {
    console.log("called");
    return true;//也可以return 1;等表示為true的值
  }
});

console.log(Object.isExtensible(p)); // "called"
                                     // true
var p = new Proxy({}, {
  preventExtensions: function(target) {
    console.log("called");
    Object.preventExtensions(target);
    return true;
  }
});

console.log(Object.preventExtensions(p)); // "called"
                                          // false                             
屬性描述符

在代理中可以分別使用defineProperty陷阱和getOwnPropertyDescriptor陷阱攔截Object.defineProperty方法和Object.getOwnPropertyDescriptor方法的調用。

defineProperty
Object.defineProperty與Reflect.defineProperty方法返回值不同,前一個返回第一個參數,后一方法,則返回操作的結果是否成功。
let target = {};
let r1 = Object.defineProperty(target, "name", { value: "target" });
console.log(r1 === target);  // true

let r2 = Reflect.defineProperty(target, "name", { value: "target"});

console.log(r2);  // true
getOwnPropertyDescriptor
Object.getOwnPropertyDescriptor 如果原始值被傳入第一個參數,內部將會對這個值進行強制轉換,轉成Object對象,而Reflect.getOwnPropertyDescriptor方法,則會報出一個錯誤。
ownKeys

這個trap可以攔截內部[[OwnPropertyKeys]]方法,通過返回數組的值可以覆寫其行為。返回的數組被用于Object.keys(),Object.getOwnPropertyNames(),Object.getOwnPropertySymbols()和Object.assign()。

let proxy = new Proxy({}, {
    ownKeys(target) {
        return Reflect.ownKeys(target).filter(key => {
            // console.log(key);
            // return true; // 可以和下面的返回做個對比,看看輸出有什么不同
            return typeof key !== "string" || key[0] !== "_";
        })
    }
});

let nameSymbol = Symbol("name");

proxy.name = "Tom";
proxy._name = "Jerry";
proxy[nameSymbol] = "Tom & Jerry";

const names = Object.getOwnPropertyNames(proxy),
      keys = Object.keys(proxy),
      symbols = Object.getOwnPropertySymbols(proxy);

console.log(names.length);
console.log(names);
console.log(keys.length);
console.log(keys);
console.log(symbols.length);
console.log(symbols);
apply & construct

MDN apply
MDN construct
這兩個代理的目標,都是函數。

const target = function() {
    return 42;
}
const proxy = new Proxy(target, {
    apply: function(tt, ta, args) {
        return Reflect.apply(tt, ta, args);
    },
    constructor(tt, ta, args) {
      return Reflect.constructor(tt, ta, args);
    }
});

console.log(typeof proxy);
console.log(proxy());
const instance = new proxy();
console.log(instance instanceof proxy);
console.log(instance instanceof target);

所以,這兩個trap,通常可以用來

驗證函數參數

不用 new 調用構造函數

覆寫抽象基類構造函數

可調用類構造函數

例子就不一一寫了,知道用法,很方便就能實現。

可撤銷代理

方法 Proxy.revocable() 創建一個可撤銷的 Proxy 對象.
MDN revocable

var revocable = Proxy.revocable({}, {
  get: function(target, name) {
    return "[[" + name + "]]";
  }
});
var proxy = revocable.proxy;
console.log(proxy.foo); // "[[foo]]"

revocable.revoke();

console.log(proxy.foo); // TypeError is thrown
proxy.foo = 1           // TypeError again
delete proxy.foo;       // still TypeError
typeof proxy            // "object", typeof doesn"t trigger any trap
在原型上進行Proxy應用

如果把代理當原型,將發生什么事呢?在JS中,一旦涉及到原型,事情往往就沒那么簡單了。如果原型是代理,而代理是透明的,僅當默認操作執行到原型上時,都會調用代理trap,這大大限制代理的能力。

const target = {};
 const newTarget = Object.create(new Proxy(target, {
     defineProperty(trapTarget, name, desc) {
         return false;
     }
 }));

 // 按原型執行順序,這個方法可以被調用到嗎?

 Object.defineProperty(newTarget, "name", { value: "newTarget" });
 console.log(newTarget.name);
 console.log(newTarget.hasOwnProperty("name"));
 // 可以看出,defineProperty方法,沒有得到調用

在Object.create中,可以用以下幾個trap

get

set

has

將代理用途類的原型

先看一個例子

function NoSuchProperty() {}

NoSuchProperty.prototype = new Proxy({}, {
    get(tt, key, receiver) {
        throw new ReferenceError(`${key} doesn"t exist `);
    }
});

class Square extends NoSuchProperty {
    constructor(length, width) {
      super();
      this.length = length;
      this.width = width;
    }
}

let shape = new Square(2, 6);
const a1 = shape.length * shape.width;
console.log(a1); // 12

let a2 = shape.length * shape.wdth; // 拋出異常

說明:wdth是個拼寫錯誤,但按JS原型機制,shape中沒有時,會去原型中查找,所以就會拋出異常。雖然代理不是shape的直接原型,存在于shape對象的原型鏈中。

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

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

相關文章

  • 《深入理解ES6》筆記——代理(Proxy)和反射(ReflectionAPI(12)

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

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

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

    shiina 評論0 收藏0
  • 深入理解ES6筆記(十一)代理(Proxy)和反射(ReflectionAPI(12)

    摘要:是陷阱函數對應的反射方法,同時也是操作的默認行為。對象外形指的是對象已有的屬性與方法的集合,由于該屬性驗證只須在讀取屬性時被觸發,因此只要使用陷阱函數。無論該屬性是對象自身的屬性還是其原型的屬性。 主要知識點:代理和反射的定義、常用的陷阱函數、可被撤銷的代理、將代理對象作為原型使用、將代理作為類的原型showImg(https://segmentfault.com/img/bVbfWr...

    explorer_ddf 評論0 收藏0
  • ES6中的代理(Proxy)和反射(Reflection

    摘要:代理和反射的定義調用可常見代替其它目標對象的代理,它虛擬化了目標,所以二者看起來功能一致。代理可攔截引擎內部目標的底層對象操作,這些底層操作被攔截后會觸發響應特定操作的陷阱函數。 代理和反射的定義 調用 new Proxy() 可常見代替其它目標 (target) 對象的代理,它虛擬化了目標,所以二者看起來功能一致。 代理可攔截JS引擎內部目標的底層對象操作,這些底層操作被攔截后會觸發...

    Markxu 評論0 收藏0

發表評論

0條評論

yearsj

|高級講師

TA的文章

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