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

資訊專欄INFORMATION COLUMN

ES6 系列之 defineProperty 與 proxy

sean / 2820人閱讀

摘要:存取描述符同時(shí)具有以下可選鍵值一個(gè)給屬性提供的方法,如果沒(méi)有則為。該方法返回值被用作屬性值。值得注意的是屬性描述符必須是數(shù)據(jù)描述符或者存取描述符兩種形式之一,不能同時(shí)是兩者。可以忽略方法的返回值。

前言

我們或多或少都聽(tīng)過(guò)“數(shù)據(jù)綁定”這個(gè)詞,“數(shù)據(jù)綁定”的關(guān)鍵在于監(jiān)聽(tīng)數(shù)據(jù)的變化,可是對(duì)于這樣一個(gè)對(duì)象:var obj = {value: 1},我們?cè)撛趺粗?obj 發(fā)生了改變呢?

definePropety

ES5 提供了 Object.defineProperty 方法,該方法可以在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性,并返回這個(gè)對(duì)象。

語(yǔ)法

Object.defineProperty(obj, prop, descriptor)

參數(shù)

obj: 要在其上定義屬性的對(duì)象。

prop:  要定義或修改的屬性的名稱。

descriptor: 將被定義或修改的屬性的描述符。

舉個(gè)例子:

var obj = {};
Object.defineProperty(obj, "num", {
    value : 1,
    writable : true,
    enumerable : true,
    configurable : true
});
//  對(duì)象 obj 擁有屬性 num,值為 1

雖然我們可以直接添加屬性和值,但是使用這種方式,我們能進(jìn)行更多的配置。

函數(shù)的第三個(gè)參數(shù) descriptor 所表示的屬性描述符有兩種形式:數(shù)據(jù)描述符和存取描述符

兩者均具有以下兩種鍵值

configurable

當(dāng)且僅當(dāng)該屬性的 configurable 為 true 時(shí),該屬性描述符才能夠被改變,也能夠被刪除。默認(rèn)為 false。

enumerable

當(dāng)且僅當(dāng)該屬性的 enumerable 為 true 時(shí),該屬性才能夠出現(xiàn)在對(duì)象的枚舉屬性中。默認(rèn)為 false。

數(shù)據(jù)描述符同時(shí)具有以下可選鍵值

value

該屬性對(duì)應(yīng)的值。可以是任何有效的 JavaScript 值(數(shù)值,對(duì)象,函數(shù)等)。默認(rèn)為 undefined。

writable

當(dāng)且僅當(dāng)該屬性的 writable 為 true 時(shí),該屬性才能被賦值運(yùn)算符改變。默認(rèn)為 false。

存取描述符同時(shí)具有以下可選鍵值

get

一個(gè)給屬性提供 getter 的方法,如果沒(méi)有 getter 則為 undefined。該方法返回值被用作屬性值。默認(rèn)為 undefined。

set

一個(gè)給屬性提供 setter 的方法,如果沒(méi)有 setter 則為 undefined。該方法將接受唯一參數(shù),并將該參數(shù)的新值分配給該屬性。默認(rèn)為 undefined。

值得注意的是:

屬性描述符必須是數(shù)據(jù)描述符或者存取描述符兩種形式之一,不能同時(shí)是兩者。這就意味著你可以:

Object.defineProperty({}, "num", {
    value: 1,
    writable: true,
    enumerable: true,
    configurable: true
});

也可以:

var value = 1;
Object.defineProperty({}, "num", {
    get : function(){
      return value;
    },
    set : function(newValue){
      value = newValue;
    },
    enumerable : true,
    configurable : true
});

但是不可以:

// 報(bào)錯(cuò)
Object.defineProperty({}, "num", {
    value: 1,
    get: function() {
        return 1;
    }
});

此外,所有的屬性描述符都是非必須的,但是 descriptor 這個(gè)字段是必須的,如果不進(jìn)行任何配置,你可以這樣:

var obj = Object.defineProperty({}, "num", {});
console.log(obj.num); // undefined
Setters 和 Getters

之所以講到 defineProperty,是因?yàn)槲覀円褂么嫒∶枋龇械?get 和 set,這兩個(gè)方法又被稱為 getter 和 setter。由 getter 和 setter 定義的屬性稱做”存取器屬性“。

當(dāng)程序查詢存取器屬性的值時(shí),JavaScript 調(diào)用 getter方法。這個(gè)方法的返回值就是屬性存取表達(dá)式的值。當(dāng)程序設(shè)置一個(gè)存取器屬性的值時(shí),JavaScript 調(diào)用 setter 方法,將賦值表達(dá)式右側(cè)的值當(dāng)做參數(shù)傳入 setter。從某種意義上講,這個(gè)方法負(fù)責(zé)“設(shè)置”屬性值。可以忽略 setter 方法的返回值。

舉個(gè)例子:

var obj = {}, value = null;
Object.defineProperty(obj, "num", {
    get: function(){
        console.log("執(zhí)行了 get 操作")
        return value;
    },
    set: function(newValue) {
        console.log("執(zhí)行了 set 操作")
        value = newValue;
    }
})

obj.value = 1 // 執(zhí)行了 set 操作

console.log(obj.value); // 執(zhí)行了 get 操作 // 1

這不就是我們要的監(jiān)控?cái)?shù)據(jù)改變的方法嗎?我們?cè)賮?lái)封裝一下:

function Archiver() {
    var value = null;
    // archive n. 檔案
    var archive = [];

    Object.defineProperty(this, "num", {
        get: function() {
            console.log("執(zhí)行了 get 操作")
            return value;
        },
        set: function(value) {
            console.log("執(zhí)行了 set 操作")
            value = value;
            archive.push({ val: value });
        }
    });

    this.getArchive = function() { return archive; };
}

var arc = new Archiver();
arc.num; // 執(zhí)行了 get 操作
arc.num = 11; // 執(zhí)行了 set 操作
arc.num = 13; // 執(zhí)行了 set 操作
console.log(arc.getArchive()); // [{ val: 11 }, { val: 13 }]
watch API

既然可以監(jiān)控?cái)?shù)據(jù)的改變,那我可以這樣設(shè)想,即當(dāng)數(shù)據(jù)改變的時(shí)候,自動(dòng)進(jìn)行渲染工作。舉個(gè)例子:

HTML 中有個(gè) span 標(biāo)簽和 button 標(biāo)簽

1

當(dāng)點(diǎn)擊按鈕的時(shí)候,span 標(biāo)簽里的值加 1。

傳統(tǒng)的做法是:

document.getElementById("button").addEventListener("click", function(){
    var container = document.getElementById("container");
    container.innerHTML = Number(container.innerHTML) + 1;
});

如果使用了 defineProperty:

var obj = {
    value: 1
}

// 儲(chǔ)存 obj.value 的值
var value = 1;

Object.defineProperty(obj, "value", {
    get: function() {
        return value;
    },
    set: function(newValue) {
        value = newValue;
        document.getElementById("container").innerHTML = newValue;
    }
});

document.getElementById("button").addEventListener("click", function() {
    obj.value += 1;
});

代碼看似增多了,但是當(dāng)我們需要改變 span 標(biāo)簽里的值的時(shí)候,直接修改 obj.value 的值就可以了。

然而,現(xiàn)在的寫(xiě)法,我們還需要多帶帶聲明一個(gè)變量存儲(chǔ) obj.value 的值,因?yàn)槿绻阍?set 中直接 obj.value = newValue 就會(huì)陷入無(wú)限的循環(huán)中。此外,我們可能需要監(jiān)控很多屬性值的改變,要是一個(gè)一個(gè)寫(xiě),也很累吶,所以我們簡(jiǎn)單寫(xiě)個(gè) watch 函數(shù)。使用效果如下:

var obj = {
    value: 1
}

watch(obj, "num", function(newvalue){
    document.getElementById("container").innerHTML = newvalue;
})

document.getElementById("button").addEventListener("click", function(){
    obj.value += 1
});

我們來(lái)寫(xiě)下這個(gè) watch 函數(shù):

(function(){
    var root = this;
    function watch(obj, name, func){
        var value = obj[name];

        Object.defineProperty(obj, name, {
            get: function() {
                return value;
            },
            set: function(newValue) {
                value = newValue;
                func(value)
            }
        });

        if (value) obj[name] = value
    }

    this.watch = watch;
})()

現(xiàn)在我們已經(jīng)可以監(jiān)控對(duì)象屬性值的改變,并且可以根據(jù)屬性值的改變,添加回調(diào)函數(shù),棒棒噠~

proxy

使用 defineProperty 只能重定義屬性的讀取(get)和設(shè)置(set)行為,到了 ES6,提供了 Proxy,可以重定義更多的行為,比如 in、delete、函數(shù)調(diào)用等更多行為。

Proxy 這個(gè)詞的原意是代理,用在這里表示由它來(lái)“代理”某些操作,ES6 原生提供 Proxy 構(gòu)造函數(shù),用來(lái)生成 Proxy 實(shí)例。我們來(lái)看看它的語(yǔ)法:

var proxy = new Proxy(target, handler);

proxy 對(duì)象的所有用法,都是上面這種形式,不同的只是handler參數(shù)的寫(xiě)法。其中,new Proxy()表示生成一個(gè)Proxy實(shí)例,target參數(shù)表示所要攔截的目標(biāo)對(duì)象,handler參數(shù)也是一個(gè)對(duì)象,用來(lái)定制攔截行為。

var proxy = new Proxy({}, {
    get: function(obj, prop) {
        console.log("設(shè)置 get 操作")
        return obj[prop];
    },
    set: function(obj, prop, value) {
        console.log("設(shè)置 set 操作")
        obj[prop] = value;
    }
});

proxy.time = 35; // 設(shè)置 set 操作

console.log(proxy.time); // 設(shè)置 get 操作 // 35

除了 get 和 set 之外,proxy 可以攔截多達(dá) 13 種操作,比如 has(target, propKey),可以攔截 propKey in proxy 的操作,返回一個(gè)布爾值。

// 使用 has 方法隱藏某些屬性,不被 in 運(yùn)算符發(fā)現(xiàn)
var handler = {
  has (target, key) {
    if (key[0] === "_") {
      return false;
    }
    return key in target;
  }
};
var target = { _prop: "foo", prop: "foo" };
var proxy = new Proxy(target, handler);
console.log("_prop" in proxy); // false

又比如說(shuō) apply 方法攔截函數(shù)的調(diào)用、call 和 apply 操作。

apply 方法可以接受三個(gè)參數(shù),分別是目標(biāo)對(duì)象、目標(biāo)對(duì)象的上下文對(duì)象(this)和目標(biāo)對(duì)象的參數(shù)數(shù)組,不過(guò)這里我們簡(jiǎn)單演示一下:

var target = function () { return "I am the target"; };
var handler = {
  apply: function () {
    return "I am the proxy";
  }
};

var p = new Proxy(target, handler);

p();
// "I am the proxy"

又比如說(shuō) ownKeys 方法可以攔截對(duì)象自身屬性的讀取操作。具體來(lái)說(shuō),攔截以下操作:

Object.getOwnPropertyNames()

Object.getOwnPropertySymbols()

Object.keys()

下面的例子是攔截第一個(gè)字符為下劃線的屬性名,不讓它被 for of 遍歷到。

let target = {
  _bar: "foo",
  _prop: "bar",
  prop: "baz"
};

let handler = {
  ownKeys (target) {
    return Reflect.ownKeys(target).filter(key => key[0] !== "_");
  }
};

let proxy = new Proxy(target, handler);
for (let key of Object.keys(proxy)) {
  console.log(target[key]);
}
// "baz"

更多的攔截行為可以查看阮一峰老師的 《ECMAScript 6 入門(mén)》

值得注意的是,proxy 的最大問(wèn)題在于瀏覽器支持度不夠,而且很多效果無(wú)法使用 poilyfill 來(lái)彌補(bǔ)。

watch API 優(yōu)化

我們使用 proxy 再來(lái)寫(xiě)一下 watch 函數(shù)。使用效果如下:

(function() {
    var root = this;

    function watch(target, func) {

        var proxy = new Proxy(target, {
            get: function(target, prop) {
                return target[prop];
            },
            set: function(target, prop, value) {
                target[prop] = value;
                func(prop, value);
            }
        });

        if(target[name]) proxy[name] = value;
        return proxy;
    }

    this.watch = watch;
})()

var obj = {
    value: 1
}

var newObj = watch(obj, function(key, newvalue) {
    if (key == "value") document.getElementById("container").innerHTML = newvalue;
})

document.getElementById("button").addEventListener("click", function() {
    newObj.value += 1
});

我們也可以發(fā)現(xiàn),使用 defineProperty 和 proxy 的區(qū)別,當(dāng)使用 defineProperty,我們修改原來(lái)的 obj 對(duì)象就可以觸發(fā)攔截,而使用 proxy,就必須修改代理對(duì)象,即 Proxy 的實(shí)例才可以觸發(fā)攔截。

ES6 系列

ES6 系列目錄地址:https://github.com/mqyqingfeng/Blog

ES6 系列預(yù)計(jì)寫(xiě)二十篇左右,旨在加深 ES6 部分知識(shí)點(diǎn)的理解,重點(diǎn)講解塊級(jí)作用域、標(biāo)簽?zāi)0濉⒓^函數(shù)、Symbol、Set、Map 以及 Promise 的模擬實(shí)現(xiàn)、模塊加載方案、異步處理等內(nèi)容。

如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤剑?qǐng)務(wù)必給予指正,十分感謝。如果喜歡或者有所啟發(fā),歡迎 star,對(duì)作者也是一種鼓勵(lì)。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/99133.html

相關(guān)文章

  • ES6】改變 JS 內(nèi)置行為的代理反射

    摘要:通過(guò)對(duì)這些底層內(nèi)置對(duì)象的代理陷阱和反射函數(shù),讓開(kāi)發(fā)者能進(jìn)一步接近引擎的能力。顯然,與要求代理目標(biāo)對(duì)象必須是一個(gè)函數(shù),這兩個(gè)代理陷阱在函數(shù)的執(zhí)行方式上開(kāi)啟了很多的可能性,結(jié)合使用就可以完全控制任意的代理目標(biāo)函數(shù)的行為。 代理(Proxy)可以攔截并改變 JS 引擎的底層操作,如數(shù)據(jù)讀取、屬性定義、函數(shù)構(gòu)造等一系列操作。ES6 通過(guò)對(duì)這些底層內(nèi)置對(duì)象的代理陷阱和反射函數(shù),讓開(kāi)發(fā)者能進(jìn)一步接...

    lushan 評(píng)論0 收藏0
  • ES6Reflect

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

    BingqiChen 評(píng)論0 收藏0
  • ES6Proxy & Reflection API

    摘要:的出現(xiàn),使用內(nèi)建對(duì)象的繼承得以實(shí)現(xiàn)。屬性不存在拋出異常是取值操作,而就是賦值操作,可以對(duì)屬性值進(jìn)行驗(yàn)證。屬性必須為數(shù)字拋出異常接受兩個(gè)參數(shù)被讀取屬性的原對(duì)象,即代理的目標(biāo)。這個(gè)可以攔截內(nèi)部方法,通過(guò)返回?cái)?shù)組的值可以覆寫(xiě)其行為。 Proxy & Reflect extends的出現(xiàn),使用內(nèi)建對(duì)象的繼承得以實(shí)現(xiàn)。Proxy可以攔截JS引擎內(nèi)部目標(biāo)的底層對(duì)象操作,這些底層操作被攔截后會(huì)觸發(fā)響...

    yearsj 評(píng)論0 收藏0
  • 深入理解ES6《代理和反射》

    摘要:使用陷阱驗(yàn)證屬性用于接收屬性代理的目標(biāo)的對(duì)象要寫(xiě)入的屬性鍵被寫(xiě)入的屬性的值操作發(fā)生的對(duì)象通常是代理屬性必須是數(shù)字拋錯(cuò)用陷阱驗(yàn)證對(duì)象結(jié)構(gòu)屬性不存在拋出錯(cuò)誤使用陷阱隱藏已有屬性可以用操作符來(lái)檢測(cè)給定對(duì)象中是否包含有某個(gè)屬性,如果自有屬性或原型屬 使用set陷阱驗(yàn)證屬性 let target = { name: target } let proxy = new Proxy(targe...

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

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

0條評(píng)論

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