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

資訊專欄INFORMATION COLUMN

淺談 JS 對(duì)象添加 getter與 setter 的5種方法以及如何讓對(duì)象屬性不可配置或枚舉

Dean / 952人閱讀

摘要:需被定義或修改的屬性名。當(dāng)且僅當(dāng)該屬性出現(xiàn)在相應(yīng)的對(duì)象枚舉屬性中。可以是任何有效的值數(shù)值,對(duì)象,函數(shù)等。方法將返回用作屬性的值。該方法將收到作為唯一參數(shù)的新值分配給屬性。屬性用來聲明欲修飾屬性是否可以被枚舉。

定義 getter 與 setter

通過對(duì)象初始化器定義

使用 Object.create 方法

使用 Object.defineProperty 方法

使用 Object.defineProperties 方法

使用 Object.prototype.__defineGetter__ 以及 Object.prototype.__defineSetter__ 方法

什么是屬性描述符

創(chuàng)建屬性不可配置不可枚舉的對(duì)象

Enumerable 特性

Configurable 特新

提高及擴(kuò)展

定義 getter 與 setter

1.通過對(duì)象初始化器在創(chuàng)建對(duì)象的時(shí)候指明(也可以稱為通過字面值創(chuàng)建對(duì)象時(shí)聲明)

(function () {
    var o = {
        a : 7,
        get b(){return this.a +1;},//通過 get,set的 b,c方法間接性修改 a 屬性
        set c(x){this.a = x/2}
    };
    console.log(o.a);
    console.log(o.b);
    o.c = 50;
    console.log(o.a);
})();

在 chrome 中調(diào)試視圖如下:

可以看到對(duì)象下多了 get 屬性以及 set 屬性
輸出結(jié)果如下:

當(dāng)然 get 語句與 set 語句可以聲明多次用來對(duì)應(yīng)多個(gè) gettersetter
使用這種方法的好處是可以在聲明屬性的時(shí)候同時(shí)聲明對(duì)應(yīng)的 gettersetter
這里就有人問了,能不能將o 對(duì)象的 getset 方法的方法名都改成 “a”,這樣就可以直接通過“.”來訪問方法直接操作

(function () {
    var o = {
        a : 7,
        get a(){return this.a +1;},//死循環(huán)
        set a(x){this.a = x/2}
    };
    console.log(o.a);
    console.log(o.b);
    o.c = 50;
    console.log(o.a);
})();

打開 chrome 查看創(chuàng)建后的視圖如下:

可以看到這個(gè)時(shí)候的 getset 方法已經(jīng)和上面不同,但是是否真的能起作用呢,答案是否定的,當(dāng)我們通過 o.a 調(diào)用的是 get語句 聲明的 a方法,進(jìn)入到該方法后遇到 this.a 方法繼續(xù)調(diào)用該方法形成死循環(huán)最終導(dǎo)致死循環(huán)報(bào)內(nèi)存溢出錯(cuò)誤。

新語法(ES6):暫時(shí)只有 firefox 支持,其他瀏覽器會(huì)報(bào)錯(cuò)

(function () {
    var b = "bb";
    var c = "cc";
    var o = {
        a : 7,
        get [b](){return this.a +1;},
        set [c](x){this.a = x/2},
    };
    console.log(o.a);
    console.log(o[b]);
    o["cc"] = 50;
    console.log(o.a);
})();

打開 firefox 查看調(diào)試:

輸出結(jié)果如下:

2.使用 Object.create 方法

引用 MDN:

概述
    Object.create() 方法創(chuàng)建一個(gè)擁有指定原型和若干個(gè)指定屬性的對(duì)象。

語法
    Object.create(proto, [ propertiesObject ])

我們都知道使用 Object.create 方法傳遞一個(gè)參數(shù)的時(shí)候可以創(chuàng)建一個(gè)以該參數(shù)為原型的對(duì)象 淺談 JS 創(chuàng)建對(duì)象的 8 種模式
第二個(gè)參數(shù)是可選項(xiàng),是一個(gè)匿名的參數(shù)對(duì)象,該參數(shù)對(duì)象是一組屬性與值,該對(duì)象的屬性名稱將是新創(chuàng)建的對(duì)象的屬性名稱,值是屬性描述符(包擴(kuò)數(shù)據(jù)描述符或存取描述符,具體解釋看后面的內(nèi)容 什么是屬性描述符)。
通過屬性描述符我們可以實(shí)現(xiàn)為新創(chuàng)建的對(duì)象添加 get 方法以及 set 方法

(function () {
    var o = null;
    o = Object.create(Object.prototype,//指定原型為 Object.prototype
            {
                bar:{
                    get :function(){
                        return 10;
                    },
                    set : function (val) {
                        console.log("Setting `o.bar` to ",val);
                    }
                }
            }//第二個(gè)參數(shù)
        );
    console.log(o.bar);
    o.bar = 12;
})();

在 chrome 中調(diào)試試圖如下:

可以看到新創(chuàng)建對(duì)象通用多了 get 以及 set 屬性
輸出結(jié)果如下:

上面這個(gè)例子并沒有用來針對(duì)的 get 方法以及 set 方法使用的屬性

(function () {
    var o = null;
    o = Object.create(Object.prototype,//指定原型為 Object.prototype
            {
                bar:{
                    get :function(){
                        return this.a;
                    },
                    set : function (val) {
                        console.log("Setting `o.bar` to ",val);
                        this.a = val;
                    },
                    configurable :true
                }
            }//第二個(gè)參數(shù)
        );
    o.a = 10;
    console.log(o.bar);
    o.bar = 12;
    console.log(o.bar);
})();

亦或:

(function () {
    var o = {a:10};
    o = Object.create(o,//指定原型為 o 這里實(shí)際可以理解為繼承
            {
                bar:{
                    get :function(){
                        return this.a;
                    },
                    set : function (val) {
                        console.log("Setting `o.bar` to ",val);
                        this.a = val;
                    },
                    configurable :true
                }
            }//第二個(gè)參數(shù)
        );
    console.log(o.bar);
    o.bar = 12;
    console.log(o.bar);
})();

輸出結(jié)果如下:

使用這種方式的好處是可配置性高,但初學(xué)者容易迷糊。

3.使用 Object.defineProperty 方法
引用 MDN:

概要
    Object.defineProperty() 方法直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)已經(jīng)存在的屬性, 并返回這個(gè)對(duì)象。
語法
    Object.defineProperty(obj, prop, descriptor)
參數(shù)
    obj
        需要定義屬性的對(duì)象。
    prop
        需被定義或修改的屬性名。
    descriptor
        需被定義或修改的屬性的描述符。
(function () {
    var o = { a : 1}//聲明一個(gè)對(duì)象,包含一個(gè) a 屬性,值為1
    Object.defineProperty(o,"b",{
        get: function () {
            return this.a;
        },
        set : function (val) {
            this.a = val;
        },
        configurable : true
    });

    console.log(o.b);
    o.b = 2;
    console.log(o.b);
})();

這個(gè)方法與前面兩種的區(qū)別是:使用前面兩種只能在聲明定義的時(shí)候指定 gettersetter,使用該方法可以隨時(shí)的添加或修改。

如果說需要一次性批量添加 getter 與 setter 也是沒問題的,使用如下方法:

4.使用 Object.defineProperties方法

MDN:

概述
    Object.defineProperties() 方法在一個(gè)對(duì)象上添加或修改一個(gè)或者多個(gè)自有屬性,并返回該對(duì)象。
語法
    Object.defineProperties(obj, props)
參數(shù)
    obj
    將要被添加屬性或修改屬性的對(duì)象
    props
    該對(duì)象的一個(gè)或多個(gè)鍵值對(duì)定義了將要為對(duì)象添加或修改的屬性的具體配置
    
    

不難看出用法與 Object.defineProperty 方法類似

(function () {
    var obj = {a:1,b:"string"};
    Object.defineProperties(obj,{
        "A":{
            get:function(){return this.a+1;},
            set:function(val){this.a = val;}
        },
        "B":{
            get:function(){return this.b+2;},
            set:function(val){this.b = val}
        }
    });

    console.log(obj.A);
    console.log(obj.B);
    obj.A = 3;
    obj.B = "hello";
    console.log(obj.A);
    console.log(obj.B);
})();

輸出結(jié)果如下:

5.使用 Object.prototype.__defineGetter__ 以及 Object.prototype.__defineSetter__ 方法

(function () {
    var o = {a:1};
    o.__defineGetter__("giveMeA", function () {
        return this.a;
    });
    o.__defineSetter__("setMeNew", function (val) {
        this.a  = val;
    })
    console.log(o.giveMeA);
    o.setMeNew = 2;
    console.log(o.giveMeA);
})();
輸出結(jié)果為1和2

查看 MDN 有如下說明:

什么是屬性描述符

MDN:

對(duì)象里目前存在的屬性描述符有兩種主要形式:數(shù)據(jù)描述符和存取描述符。

數(shù)據(jù)描述符是一個(gè)擁有可寫或不可寫值的屬性。

存取描述符是由一對(duì) getter-setter 函數(shù)功能來描述的屬性。

描述符必須是兩種形式之一;不能同時(shí)是兩者。

數(shù)據(jù)描述符和存取描述符均具有以下可選鍵值:

configurable
    當(dāng)且僅當(dāng)這個(gè)屬性描述符值為 true 時(shí),該屬性可能會(huì)改變,也可能會(huì)被從相應(yīng)的對(duì)象刪除。默認(rèn)為 false。
enumerable  
    true 當(dāng)且僅當(dāng)該屬性出現(xiàn)在相應(yīng)的對(duì)象枚舉屬性中。默認(rèn)為 false。

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

value 
    與屬性相關(guān)的值??梢允侨魏斡行У?JavaScript 值(數(shù)值,對(duì)象,函數(shù)等)。默認(rèn)為 undefined。
writable 
    true 當(dāng)且僅當(dāng)可能用 賦值運(yùn)算符 改變與屬性相關(guān)的值。默認(rèn)為 false。

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

get 
    一個(gè)給屬性提供 getter 的方法,如果沒有 getter 則為 undefined。方法將返回用作屬性的值。默認(rèn)為 undefined。
set
    一個(gè)給屬性提供 setter 的方法,如果沒有 setter 則為 undefined。該方法將收到作為唯一參數(shù)的新值分配給屬性。默認(rèn)為 undefined。

以上是摘自MDN的解釋,看起來是很晦澀的,具體什么意思呢:
首先我們從以上解釋知道該匿名參數(shù)對(duì)象有個(gè)很好聽的名字叫屬性描述符,屬性描述符又分成兩大塊:數(shù)據(jù)描述符以及存取描述符(其實(shí)只是一個(gè)外號(hào),給指定的屬性集合起個(gè)外號(hào))。

數(shù)據(jù)描述符包括兩個(gè)屬性 : value 屬性以及 writable 屬性,第一個(gè)屬性用來聲明當(dāng)前欲修飾的屬性的值,第二個(gè)屬性用來聲明當(dāng)前對(duì)象是否可寫即是否可以修改

存取描述符就包括 getset 屬性用來聲明欲修飾的象屬性的 gettersetter

屬性描述符內(nèi)部,數(shù)據(jù)描述符與存取描述符只能存在其中之一,但是不論使用哪個(gè)描述符都可以同時(shí)設(shè)置 configurable 屬性以及enumerable 屬性。
configurable屬性用來聲明欲修飾的屬性是否能夠配置,僅有當(dāng)其值為 true 時(shí),被修飾的屬性才有可能能夠被刪除,或者重新配置。
enumerable 屬性用來聲明欲修飾屬性是否可以被枚舉

知道了什么是屬性描述符,我們就可以開始著手創(chuàng)建一些對(duì)象并開始配置其屬性

創(chuàng)建屬性不可配置不可枚舉的對(duì)象

//使用默認(rèn)值配置
(function () {
    var obj = {};//聲明一個(gè)空對(duì)象
    Object.defineProperty(obj,"key",{
        value:"static"
                        //沒有設(shè)置 enumerable 使用默認(rèn)值 false
                        //沒有 configurable 使用默認(rèn)值 false
                        //沒有 writable 使用默認(rèn)值 false
    });

    console.log(obj.key);           //輸出 “static”
    obj.key = "new"                 //嘗試修改其值,修改將失敗,因?yàn)?writable 為 false
    console.log(obj.key);           //輸出 “static”
    obj.a = 1;//動(dòng)態(tài)添加一個(gè)屬性
    for(var item in obj){ //遍歷所有 obj 的可枚舉屬性
         console.log(item);
    }//只輸出一個(gè) “a” 因?yàn)?“key”的 enumerable為 false
})();
//顯示配置 等價(jià)于上面
(function () {
    var obj = {};
    Object.defineProperty(obj,"key",{
        enumerable : false,
        configurable : false,
        writable : false,
        value : "static"
    })
})();
//等價(jià)配置
(function () {
    var o = {};
    o.a = 1;
    //等價(jià)于
    Object.defineProperty(o,"a",{value : 1,
                                writable : true,
                                configurable : true,
                                enumerable : true});
    
    Object.defineProperty(o,"a",{value :1});
    //等價(jià)于
    Object.defineProperty(o,"a",{value : 1,
                                writable : false,
                                configurable : false,
                                enumerable : false});
})();

Enumerable 特性
屬性特性 enumerable 決定屬性是否能被 for...in 循環(huán)或 Object.keys 方法遍歷得到

(function () {
    var o = {};
    Object.defineProperty(o,"a",{value :1,enumerable :true});
    Object.defineProperty(o,"b",{value :2,enumerable :false});
    Object.defineProperty(o,"c",{value :2});//enumerable default to false
    o.d = 4;//如果直接賦值的方式創(chuàng)建對(duì)象的屬性,則這個(gè)屬性的 enumerable 為 true

    for(var item in o){ //遍歷所有可枚舉屬性包括繼承的屬性
        console.log(item);
    }

    console.log(Object.keys(o));//獲取 o 對(duì)象的所有可遍歷屬性不包括繼承的屬性

    console.log(o.propertyIsEnumerable("a"));//true
    console.log(o.propertyIsEnumerable("b"));//false
    console.log(o.propertyIsEnumerable("c"));//false
})();

輸出結(jié)果如下:

Configurable 特性

(function () {
    var o = {};
    Object.defineProperty(o,"a",{get: function () {return 1;},
                                configurable : false} );
                                //enumerable 默認(rèn)為 false,
                                //value 默認(rèn)為 undefined,
                                //writable 默認(rèn)為 false,
                                //set 默認(rèn)為 undefined
                                  
    //拋出異常,因?yàn)樽铋_始定義了 configurable 為 false,故后期無法對(duì)其進(jìn)行再配置
    Object.defineProperty(o,"a",{configurable : true} );
    //拋出異常,因?yàn)樽铋_始定義了 configurable 為 false,故后期無法對(duì)其進(jìn)行再配置,enumerable 的原值為 false
    Object.defineProperty(o,"a",{enumerable : true} );
    //拋出異常,因?yàn)樽铋_始定義了 configurable 為 false,set的原值為 undefined
    Object.defineProperty(o,"a",{set : function(val){}} );
    //拋出異常,因?yàn)樽铋_始定義了 configurable 為 false,故無法進(jìn)行覆蓋,盡管想用一樣的來覆蓋
    Object.defineProperty(o,"a",{get : function(){return 1}});
    //拋出異常,因?yàn)樽铋_始定義了 configurable 為 false,故無法將其進(jìn)行重新配置把屬性描述符從存取描述符改為數(shù)據(jù)描述符
    Object.defineProperty(o,"a",{value : 12});

    console.log(o.a);//輸出1
    delete o.a;      //想要?jiǎng)h除屬性,將失敗
    console.log(o.a);//輸出1
    
})();

提高及擴(kuò)展
1.屬性描述符中容易被誤導(dǎo)的地方之 writableconfigurable

(function () {
    var o = {};
    Object.defineProperties(o,{
        "a": {
            value:1,
            writable:true,//可寫
            configurable:false//不可配置
            //enumerable 默認(rèn)為 false 不可枚舉
        },
        "b":{
            get :function(){
                return this.a;
            },
            configurable:false
        }
    });
    console.log(o.a);   //1
    o.a = 2;            //修改值成功,writable 為 true
    console.log(o.a);   //2
    Object.defineProperty(o,"a",{value:3});//同樣為修改值成功
    console.log(o.a);   //3

    //將其屬性 b 的屬性描述符從存取描述符重新配置為數(shù)據(jù)描述符
    Object.defineProperty(o,"b",{value:3});//拋出異常,因?yàn)?configurable 為 false
})();

2.通過上面的學(xué)習(xí),我們都知道傳遞屬性描述符參數(shù)時(shí),是定義一個(gè)匿名的對(duì)象,里面包含屬性描述符內(nèi)容,若每定義一次便要?jiǎng)?chuàng)建一個(gè)匿名對(duì)象傳入,將會(huì)造成內(nèi)存浪費(fèi)。故優(yōu)化如下:

(function () {
    var obj = {};

    //回收同一對(duì)象,即減少內(nèi)存浪費(fèi)
    function withValue(value){
        var d = withValue.d ||(
            withValue.d = {
                enumerable : false,
                configurable : false,
                writable : false,
                value :null
            }
            );
        d.value = value;
        return d;
    }
    Object.defineProperty(obj,"key",withValue("static"))
})();

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

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

相關(guān)文章

  • 淺談 JS 對(duì)象之?dāng)U展、密封及凍結(jié)三大特性

    摘要:嘗試刪除一個(gè)密封對(duì)象的屬性或者將某個(gè)密封對(duì)象的屬性從數(shù)據(jù)屬性轉(zhuǎn)換成訪問器屬性,結(jié)果會(huì)靜默失敗或拋出異常嚴(yán)格模式。 擴(kuò)展特性 Object.isExtensible 方法 Object.preventExtensions 方法 密封特性 Object.isSealed 方法 Object.seal 方法 凍結(jié)特性 Object.isFrozen 方法 Object...

    ChristmasBoy 評(píng)論0 收藏0
  • JavaScript || 對(duì)象

    摘要:通過對(duì)返回字符串切片第位到倒數(shù)第位即可獲得對(duì)象的類型。測(cè)試對(duì)象是的深拷貝是的子集,不能表示中所有值。序列化結(jié)果是,對(duì)象序列化結(jié)果是日期字符串不能表示函數(shù)對(duì)象和只能序列化對(duì)象自有的可枚舉屬性。 對(duì)象 對(duì)象是JavaScript的基本數(shù)據(jù)類型:屬性的無序集合。每個(gè)屬性key: value和屬性描述符descripter組成。 屬性名key:字符串或合法的變量標(biāo)識(shí)符; 屬性值value:...

    lavor 評(píng)論0 收藏0
  • JS基礎(chǔ)05對(duì)象

    摘要:對(duì)象是的數(shù)據(jù)類型。對(duì)象是動(dòng)態(tài)的,可以隨時(shí)新增和刪除自有屬性??蛻舳酥斜硎揪W(wǎng)頁結(jié)構(gòu)的對(duì)象均是宿主對(duì)象。提供第二個(gè)可選參數(shù),用以對(duì)對(duì)象的屬性進(jìn)行進(jìn)一步描述。沒有原型的對(duì)象為數(shù)不多,就是其中之一。運(yùn)算符的左側(cè)是屬性名字符串,右側(cè)是對(duì)象。 對(duì)象是 JavaScript 的數(shù)據(jù)類型。它將很多值(原始值或者其他對(duì)象)聚合在一起,可通過名字訪問這些值,因此我們可以把它看成是從字符串到值的映射。對(duì)象是...

    frolc 評(píng)論0 收藏0
  • 《JavaScript 闖關(guān)記》之對(duì)象

    摘要:屬性名可以是包含空字符串在內(nèi)的任意字符串,但對(duì)象中不能存在兩個(gè)同名的屬性??蛻舳酥斜硎揪W(wǎng)頁結(jié)構(gòu)的對(duì)象均是宿主對(duì)象。這里的函數(shù)稱做構(gòu)造函數(shù),構(gòu)造函數(shù)用以初始化一個(gè)新創(chuàng)建的對(duì)象。通過關(guān)鍵字和構(gòu)造函數(shù)調(diào)用創(chuàng)建的對(duì)象的原型就是構(gòu)造函數(shù)的屬性的值。 對(duì)象是 JavaScript 的數(shù)據(jù)類型。它將很多值(原始值或者其他對(duì)象)聚合在一起,可通過名字訪問這些值,因此我們可以把它看成是從字符串到值的映射...

    rozbo 評(píng)論0 收藏0
  • JavaScript對(duì)象詳解

    摘要:屬性描述符升級(jí)打怪必備技能對(duì)象有自己的屬性和方法,對(duì)于我們對(duì)象的屬性來講,屬性還有自己的屬性,又稱為屬性描述符。這個(gè)方法接受三個(gè)參數(shù),第一個(gè)是指定的對(duì)象,第二個(gè)是指定的對(duì)象參數(shù),第三個(gè)當(dāng)然是要修改的屬性描述符了。 對(duì)象的聲明有倆種: 字面量 通過new一個(gè)構(gòu)造函數(shù)Object 兩者唯一的區(qū)別就是,字面量形式,可以一次賦值多個(gè),通過new Object就得一個(gè)一個(gè)賦值 數(shù)據(jù)類型 ...

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

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

0條評(píng)論

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