亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

ES6 中的 Reflect 和 Proxy

wzyplus / 2696人閱讀

摘要:是中新增的特性。首先來說,的提出是為了整合之前中存在的一些不太合理的地方。表示當(dāng)前對象是否可擴(kuò)展,返回一個(gè)布爾值。更完美的枚舉很多代碼使用字符串普通或凍結(jié)的對象作為枚舉。通過記錄這些訪問和修改信息,能記錄下對這個(gè)對象的所有操作記錄。

Reflect

Reflect 是ES6中新增的特性。它是一個(gè)普通對象,下面有13個(gè)靜態(tài)方法(enumerate在最終的發(fā)布版中被移除),可以再全局下訪問。它不能當(dāng)做函數(shù)調(diào)用,也不可以用new操作符生成一個(gè)實(shí)例。

首先來說,Reflect的提出是為了整合之前JS中存在的一些不太合理的地方。

1)更加有用的返回值

Object.getOwnPropertyNames(Reflect)
// ["defineProperty", "deleteProperty", "apply", "construct", "get", "getOwnPropertyDescriptor", "getPrototypeOf", "has", "isExtensible", "ownKeys", "preventExtensions", "set", "setPrototypeOf"]
Reflect.apply

功能跟Function.prototype.apply類似。

var a = [1,2,3];
Math.max.apply(null, a);// 3
Reflect.apply(Math.max, null, a); // 3
Reflect.isExtensible / Reflect.preventExtensions

Reflect.preventExtensions用于讓一個(gè)對象變?yōu)椴豢蓴U(kuò)展。它返回一個(gè)布爾值,表示是否操作成功。
Reflect.isExtensible表示當(dāng)前對象是否可擴(kuò)展, 返回一個(gè)布爾值。

var o = {};

Reflect.isExtensible(o);// true
Object.isExtensible(o);// true

Object.freeze(o);

Reflect.isExtensible(o);// false
Object.isExtensible(o);// false

// 這兩方法的區(qū)別
Object.isExtensible(1) // false
Reflect.isExtensible(1) // 報(bào)錯(cuò)

var newO = {};
Reflect.isExtensible(newO);// true
Reflect.preventExtensions(newO); // true   返回true,表示該操作成功
Reflect.isExtensible(newO);// false
Reflect.set / Reflect.get

設(shè)置和獲取對象屬性, 這兩個(gè)方法還允許接受一個(gè)reciever,用于重定義setter和getter方法的上下文。

var o = {};
Reflect.set(o, "key", "value");
console.log(o); // {key: "value"}

Reflect.get(o, "key"); // "value"
Reflect.get(o, "nokey"); // undefined

下面演示一下receiver的使用方法

var o = {
    name: "O"
}

Object.defineProperty(o, "sayHi", {
    get(){
        return "hi, I am " + this.name
    }
})

o.sayHi; // "hi, I am O"

var receiver = {
    name: "receiver"
}
// 下面是關(guān)鍵, 看好咯~
Reflect.get(o, "sayHi", receiver); // "hi, I am receiver"

// 下面試驗(yàn)了下Proxy的用法,可以忽略
var p = new Proxy(o, {
    get(o, k, p){
        return o[k] ? Reflect.get(o, k, receiver) : undefined;
    },
    set(o, k, v, p){
        v += +new Date();
        Reflect.set(o, k, v, p)
    }
});
p.sayHi; // "hi, I am receiver"
p.t = "time:";
p.t; // "time:1530865528713"
Reflect.ownKeys

Reflect.ownKeys方法用于返回對象的所有屬性數(shù)組。
這個(gè)數(shù)組的排序是根據(jù): 先顯示數(shù)字, 數(shù)字根據(jù)大小排序,然后是 字符串根據(jù)插入的順序排序, 最后是symbol類型的key也根據(jù)插入插入順序排序。
出現(xiàn)這種排序是因?yàn)椋憬o一個(gè)對象屬性賦值時(shí)候, 對象的key的排序規(guī)則就是先數(shù)字, 在字符串, 最后是symbol類型的數(shù)據(jù)。

Reflect.ownKeys(JSON); // ["parse", "stringify", Symbol(Symbol.toStringTag)]
Object.getOwnPropertyNames(JSON); // ["parse", "stringify"]
Object.getOwnPropertySymbols(JSON); // [Symbol(Symbol.toStringTag)]
Reflect.has

用于判斷對象是否具有某個(gè)屬性

Reflect.has(JSON, "parse"); // true
Reflect.has(JSON, "nokeyxx"); // false
Reflect.has(1, "parse");// Uncaught TypeError: Reflect.has called on non-object
Reflect.construct

功能類似于new操作符

var a = new Array(3);
console.log(a); // [empty × 3]

var b =  Reflect.construct(Array, [3])
console.log(b); // [empty × 3]
Reflect.defineProperty / Reflect.deleteProperty

Reflect.defineProperty 對應(yīng)于Object.DefineProperty;
Reflect.deleteProperfy 對應(yīng)于 delete 語句;

var o = {};
Object.defineProperty(o, "sayHi", {
    configurable: true,
    get(k){
        return this[k] ? "Hi, I am " + this[k] : "I have no name";
    }
});

o.sayHi;// "I have no name"

Reflect.defineProperty(o, "sayHello", {
    configurable: true,
    get(k){
        return this[k] ? "Hi, I am " + this[k] : "I have no name";
    }
})
o.sayHello; // "I have no name"

//  演示屬性刪除方法
delete o.sayHi; // true
Reflect.deleteProperty(o, "sayHello"); // true
Reflect.setPrototypeOf / Reflect.getPrototypeOf

這兩個(gè)方法用于設(shè)置和訪問對象的原型__proto__

function A(){}; 
A.prototype.name= "A";
Reflect.getPrototypeOf(A)
// ? () { [native code] }

var a = new A();
Reflect.getPrototypeOf(a)
// {name: "A", constructor: ?}

a.name; // "A"


var c = {};
Reflect.setPrototypeOf(c, A.prototype);
c.name; // "A"
A.prototype.newName = "C";
c.newName; // "C"
Reflect.getOwnPropertyDescriptor

基本等同于Object.getOwnPropertyDescriptor,用于得到指定屬性的描述對象。

Reflect.getOwnPropertyDescriptor(JSON, "parse"); // {value: ?, writable: true, enumerable: false, configurable: true}
var c = {};
Reflect.defineProperty(c, "name", {
    configurable: true,
    enumerable: true,
    value: "CCC",
    writable: false
});

Reflect.getOwnPropertyDescriptor(c, "name");  // {value: "CCC", writable: false, enumerable: true, configurable: true}

c.name; // "CCC"
c.name = 111;
c.name; // "CCC", 因?yàn)閣ritable=== false
Proxy

Proxy 對象用于定義JS對象的基本操作行為(如屬性查找,賦值,枚舉,函數(shù)調(diào)用等)。

下面看一個(gè)修改對象get行為的demo:

var obj = { n : 1};
var p = new Proxy(obj, {
    get(t, k){
        if( Reflect.has(t, k) ){
            return t[k] + 100;
        } else {
            throw Error("no the property") 
        }
    }
});

p.n; // 101
p.p; // Uncaught Error: no the property

關(guān)于Proxy具體可以重新定義哪些基本操作:

defineProperty

deleteProperty

apply

construct

get

getOwnPropertyDescriptor

getPrototypeOf

has

isExtensible

ownKeys

preventExtensions

set

setPrototypeOf

這個(gè)列表跟 Reflect 具有的靜態(tài)方法是一致的。更多信息可以參考Proxy可以處理的方法列表 的描述

不說上面這些值基本操作,我們列舉下一下Proxy的一些使用場景。

設(shè)置默認(rèn)值

如果訪問一個(gè)對象中還沒有初始化的值,Proxy可以通過代理get方法,返回一個(gè)默認(rèn)值。

    function setDefault(defaults) {
        const handler = {
            get(t, k) {
                return Reflect.get(t, k) || defaults[k];
            }
        }

        return new Proxy({},handler);
    }

    const d = setDefault({
        name: "name"
    });

    const log = console.log;

    log(d.name); // "name"
    d.name = "new name";
    log(d.name); // "new name"
    log(d);
隱藏私有屬性

Proxy可以代理對象的基礎(chǔ)操作,我們通過代理 get 方法,控制外部對對象內(nèi)部屬性的方法。這樣便可以達(dá)到隱藏某些特性(私有屬性)的目的。

    const log = console.log;

    function hideProp(obj,filter) {
        const handler = {
            get(t, k) {
                if(!filter(k)){
                    let v = Reflect.get(t, k);
                    if(typeof v === "function"){
                        v = v.bind(t);
                    }
                    return v;
                }
                
            }
        }

        return new Proxy(obj,handler);
    }

    function filter(key){
        return key[0] === "_";
    }

    const o = {
        _p : "no access",
        p: "access",
        f: function(){
            log(this._p);
        }
    };

    const p = hideProp(o, filter);

    log(p.p); // access
    log(p._p); // undefined
    log(p.f());   // no access
更完美的枚舉

很多JavaScript代碼使用字符串、普通或凍結(jié)的對象作為枚舉。這些解決方案有其類型的安全問題,而且通常容易出錯(cuò)。

Proxy可以提供一個(gè)可行的替代方案。我們采用一個(gè)簡單的鍵值對象,并通過保護(hù)它免受(甚至無意的)修改而使其更加健壯。甚至比Object.freeze更加完善。(Object.freeze不允許修改,但不會(huì)引發(fā)錯(cuò)誤,而是靜默報(bào)錯(cuò))

    const log = console.log;

    function enumF(obj) {
        const handler = {
            get(t, k) {
                if(Reflect.has(t, k)){
                    let v = Reflect.get(t, k);
                    if(typeof v === "function"){
                        v = v.bind(t);
                    }
                    return v;
                }
                
            },
            set(t){
                throw new TypeError("Enum is read only");
            }
        }

        return new Proxy(obj,handler);
    }

    const o = {
        p: "access",
        f: function(){
            log(this._p);
        }
    };

    const p = enumF(o);

    log(p.p); // access
    p.p = "modified";  // TypeError

    // 對比Object.freeze
    const o1 = {
        p: "1"
    }
    Object.freeze(o1);
    o1.p = "modified";
    log(o1.p);
跟蹤對象變化

因?yàn)镻roxy可以截獲對象的大部分基礎(chǔ)操作,因此我們實(shí)際上是可以跟蹤的對 對象的訪問和修改。通過記錄這些訪問和修改信息,能記錄下對這個(gè)對象的所有操作記錄。

    const log = console.log;

    function trackChange(obj, onchange) {
        const handler = {
            deleteProperty(t, k){
                const oldVal = t[k];
                Reflect.deleteProperty(t, k);
                onchange(t, k , undefined, oldVal)
            },
            set(t,k, v){
                const oldVal = t[k];
                Reflect.set(t, k , v);
                onchange(t, k, v, oldVal);
            }
        }

        return new Proxy(obj,handler);
    }

    const o = {
        p: "access",
        f: function(){
            log(this._p);
        }
    };

    const p = trackChange(o, (t,k,newV, oldV)=>{
        log(`the property: ${k} change from old value [${oldV}] to new value [${newV}]`)
    });

    
    p.p = "modified";

    delete p.f;
Proxy實(shí)現(xiàn)單例模式

來看看通過Proxy如何實(shí)現(xiàn) 單例模式。

    const log = console.log;

    function singleInstance(obj){
        let instance,
            handler = {
                construct:function(t){
                    if(!instance){
                        instance = Reflect.construct(...arguments);
                    }
                    return instance;
                }
            }

        return new Proxy(obj, handler);
    }

    function A(){
        this.v = 1;
    }

    const p = singleInstance(A);

    const p1 = new p();
    const p2 = new p();

    log(p1.v);
    log(p2.v);
    p1.v = "new value";
    log(p1.v);
    log(p2.v);
總結(jié)

總結(jié)一下,上面的幾個(gè)例子中,我們基本上代理的都是對象的get,set,deleteProperty方法。這些都是對象的常見操作。用好了Proxy可以解決很多問題,例如vue.js數(shù)據(jù)雙向綁定的特性實(shí)際上也可以使用Proxy實(shí)現(xiàn)。

說了這么多,但是并不極力推薦使用Proxy,并不是出于兼容性問題。主要是性能方面,可以肯定的是,使用了Proxy肯定不如原有對象訪問速度更快。Proxy相當(dāng)于在對象前添加了一道墻,任何操作都要先經(jīng)過Proxy處理。這肯定會(huì)增加成本。寫這篇文章的主要目的是 希望能夠了解更多的東西,為自己解決問題增加另外一種方案。

【參考資料】

ecma 262:Reflect

為什么要使用Reflect的原因

實(shí)例解析 ES6 Proxy 使用場景

ES6 Features - 10 Use Cases for Proxy

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

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/108182.html

相關(guān)文章

  • ES6 Proxy/Reflect 淺析

    摘要:即必須有返回值其中可接受三個(gè)參數(shù),為目標(biāo)對象,為屬性名,為實(shí)際接受的對象,默認(rèn)為本例中新建的,如果單獨(dú)指出一個(gè)對象,可使指出對象受到相同的方法作用。且中的必須有返回值,的不用,這也正是因?yàn)樵谒筮€會(huì)執(zhí)行所以不需要。 ES6 Proxy/Reflect Proxy 攔截器 proxy是es6的新特性,簡單來講,即是對目標(biāo)對象的屬性讀取、設(shè)置,亦或函數(shù)調(diào)用等操作進(jìn)行攔截(處理)。 let...

    Juven 評論0 收藏0
  • ES6學(xué)習(xí)筆記4-ProxyReflect、Decorator、Module

    摘要:攔截實(shí)例作為構(gòu)造函數(shù)調(diào)用的操作,比如。方法等同于,這提供了一種不使用,來調(diào)用構(gòu)造函數(shù)的方法。方法對應(yīng),返回一個(gè)布爾值,表示當(dāng)前對象是否可擴(kuò)展。這是的一個(gè)提案,目前轉(zhuǎn)碼器已經(jīng)支持。別名或修飾器在控制臺(tái)顯示一條警告,表示該方法將廢除。 Proxy Proxy 這個(gè)詞的原意是代理,用在這里表示由它來代理某些操作,可以譯為代理器,即用自己的定義覆蓋了語言的原始定義。ES6 原生提供 Proxy...

    lushan 評論0 收藏0
  • JavaScript 中的 ES6 Proxy

    摘要:下面是實(shí)現(xiàn)的函數(shù)為異步函數(shù)添加自動(dòng)超時(shí)功能超時(shí)時(shí)間異步函數(shù)包裝后的異步函數(shù)測試一下,是可以正常調(diào)用與訪問其上的屬性的好了,這便是吾輩最常用的一種方式了封裝高階函數(shù),為函數(shù)添加某些功能。 JavaScript 中的 ES6 Proxy 吾輩博客的原文地址: https://blog.rxliuli.com/p/c3... 場景 就算只是扮演,也會(huì)成為真實(shí)的自我的一部分。對人類的精神來說...

    cucumber 評論0 收藏0
  • ES6Reflect

    摘要:查找并返回對象的屬性例例屬性部署了讀取函數(shù)返回的是的參數(shù)對象注意如果的第一個(gè)參數(shù)不是對象,則會(huì)報(bào)錯(cuò)。它返回一個(gè)布爾值,表示是否操作成功用于返回對象的所有屬性使用和實(shí)現(xiàn)觀察者模式請參考觀察者模式 1、什么是Reflect?為操作對象而提供的新API 2、為什么要設(shè)計(jì)Reflect?(1)將Object對象的屬于語言內(nèi)部的方法放到Reflect對象上,即從Reflect對象上拿Object...

    BingqiChen 評論0 收藏0
  • 【資源集合】 ES6 元編程(Proxy & Reflect & Symbol)

    摘要:理解元編程和是屬于元編程范疇的,能介入的對象底層操作進(jìn)行的過程中,并加以影響。元編程中的元的概念可以理解為程序本身。中,便是兩個(gè)可以用來進(jìn)行元編程的特性。在之后,標(biāo)準(zhǔn)引入了,從而提供比較完善的元編程能力。 導(dǎo)讀 幾年前 ES6 剛出來的時(shí)候接觸過 元編程(Metaprogramming)的概念,不過當(dāng)時(shí)還沒有深究。今天在應(yīng)用和學(xué)習(xí)中不斷接觸到這概念,比如 mobx 5 中就用到了 Pr...

    aikin 評論0 收藏0

發(fā)表評論

0條評論

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