JS對象添加getter與setter的5種方法

定義 getter 與 setter

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

(function(){

varo?=?{

a:7,

get?b(){returnthis.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)試視圖如下:

可以看到對象下多了?get?屬性以及?set?屬性

當(dāng)然?get?語句與?set?語句可以聲明多次用來對應(yīng)多個?getter?和?setter

使用這種方法的好處是可以在聲明屬性的時候同時聲明對應(yīng)的?getter?和?setter

這里就有人問了提茁,能不能將o 對象的?get?及?set?方法的方法名都改成 “a”,這樣就可以直接通過“.”來訪問方法直接操作

(function(){

varo?=?{

a:7,

get?a(){returnthis.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)建后的視圖如下:?

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

新語法(ES6):暫時只有 firefox 支持,其他瀏覽器會報錯

(function(){

varb?="bb";

varc?="cc";

varo?=?{

a:7,

get?[b](){returnthis.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)建一個擁有指定原型和若干個指定屬性的對象。 語法 Object.create(proto, [ propertiesObject ])

我們都知道使用?Object.create?方法傳遞一個參數(shù)的時候可以創(chuàng)建一個以該參數(shù)為原型的對象载碌。

第二個參數(shù)是可選項,是一個匿名的參數(shù)對象衅枫,該參數(shù)對象是一組屬性與值嫁艇,該對象的屬性名稱將是新創(chuàng)建的對象的屬性名稱,值是屬性描述符(包擴(kuò)數(shù)據(jù)描述符或存取描述符弦撩,具體解釋看后面的內(nèi)容 什么是屬性描述符)步咪。

通過屬性描述符我們可以實現(xiàn)為新創(chuàng)建的對象添加?get?方法以及?set?方法

(function(){

varo?=null;

o?=Object.create(Object.prototype,//指定原型為?Object.prototype

{

bar:{

get:function(){

return10;

},

set:function(val){

console.log("Setting?`o.bar`?to?",val);

}

}

}//第二個參數(shù)

);

console.log(o.bar);

o.bar?=12;

})();

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

可以看到新創(chuàng)建對象通用多了?get?以及?set?屬性。

輸出結(jié)果如下:?

上面這個例子并沒有用來針對的?get?方法以及?set?方法使用的屬性

(function(){

varo?=null;

o?=Object.create(Object.prototype,//指定原型為?Object.prototype

{

bar:{

get:function(){

returnthis.a;

},

set:function(val){

console.log("Setting?`o.bar`?to?",val);

this.a?=?val;

},

configurable:true

}

}//第二個參數(shù)

);

o.a?=10;

console.log(o.bar);

o.bar?=12;

console.log(o.bar);

})();

亦或:

(function(){

varo?=?{a:10};

o?=Object.create(o,//指定原型為?o?這里實際可以理解為繼承

{

bar:{

get:function(){

returnthis.a;

},

set:function(val){

console.log("Setting?`o.bar`?to?",val);

this.a?=?val;

},

configurable:true

}

}//第二個參數(shù)

);

console.log(o.bar);

o.bar?=12;

console.log(o.bar);

})();

輸出結(jié)果如下:

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

3.使用?Object.defineProperty?方法

引用 MDN:

概要 Object.defineProperty() 方法直接在一個對象上定義一個新屬性,或者修改一個已經(jīng)存在的屬性感凤, 并返回這個對象悯周。 語法 Object.defineProperty(obj, prop, descriptor) 參數(shù) obj 需要定義屬性的對象。 prop 需被定義或修改的屬性名陪竿。 descriptor 需被定義或修改的屬性的描述符禽翼。

(function?()?{??var?o?=?{?a?:?1}//聲明一個對象,包含一個?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);

})();

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

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

4.使用?Object.defineProperties方法

MDN:

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

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

(function(){

varobj?=?{a:1,b:"string"};

Object.defineProperties(obj,{

"A":{

get:function(){returnthis.a+1;},

set:function(val){this.a?=?val;}

},

"B":{

get:function(){returnthis.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(){

varo?=?{a:1};

o.__defineGetter__("giveMeA",function(){

returnthis.a;

});

o.__defineSetter__("setMeNew",function(val){

this.a?=?val;

})

console.log(o.giveMeA);

o.setMeNew?=2;

console.log(o.giveMeA);

})();

輸出結(jié)果為1和2 查看 MDN 有如下說明:?

順便給大家推薦一個裙长酗,它的前面是 537,中間是631姐仅,最后就是 707花枫。想要學(xué)習(xí)前端的小伙伴可以加入我們一起學(xué)習(xí),互相幫助掏膏。群里每天晚上都有大神免費直播上課劳翰,如果不是想學(xué)習(xí)的小伙伴就不要加啦。(537-631-707)

二馒疹、什么是屬性描述符佳簸?

MDN:

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

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

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

描述符必須是兩種形式之一听想;不能同時是兩者。

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

value 與屬性相關(guān)的值马胧『郝颍可以是任何有效的 JavaScript 值(數(shù)值,對象佩脊,函數(shù)等)蛙粘。默認(rèn)為 undefined。 writable true 當(dāng)且僅當(dāng)可能用 賦值運(yùn)算符 改變與屬性相關(guān)的值威彰。默認(rèn)為 false出牧。

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

get

一個給屬性提供 getter 的方法,如果沒有 getter 則為 undefined歇盼。方法將返回用作屬性的值舔痕。默認(rèn)為 undefined。 set 一個給屬性提供 setter 的方法豹缀,如果沒有 setter 則為 undefined伯复。該方法將收到作為唯一參數(shù)的新值分配給屬性。默認(rèn)為 undefined耿眉。

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

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

存取描述符就包括get與set屬性用來聲明欲修飾的象屬性的getter及setter

屬性描述符內(nèi)部,數(shù)據(jù)描述符與存取描述符只能存在其中之一铛纬,但是不論使用哪個描述符都可以同時設(shè)置configurable屬性以及enumerable屬性厌均。

configurable屬性用來聲明欲修飾的屬性是否能夠配置,僅有當(dāng)其值為true時告唆,被修飾的屬性才有可能能夠被刪除棺弊,或者重新配置。

enumerable屬性用來聲明欲修飾屬性是否可以被枚舉擒悬。

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

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

//使用默認(rèn)值配置

(function(){

varobj?=?{};//聲明一個空對象

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"http://嘗試修改其值,修改將失敗,因為?writable?為?false

console.log(obj.key);//輸出?“static”

obj.a?=1;//動態(tài)添加一個屬性

for(variteminobj){//遍歷所有?obj?的可枚舉屬性

console.log(item);

}//只輸出一個?“a”?因為?“key”的?enumerable為?false

})();

//顯示配置?等價于上面

(function(){

varobj?=?{};

Object.defineProperty(obj,"key",{

enumerable:false,

configurable:false,

writable:false,

value:"static"

})

})();

//等價配置

(function(){

varo?=?{};

o.a?=1;

//等價于

Object.defineProperty(o,"a",{value:1,

writable:true,

configurable:true,

enumerable:true});

Object.defineProperty(o,"a",{value:1});

//等價于

Object.defineProperty(o,"a",{value:1,

writable:false,

configurable:false,

enumerable:false});

})();

四懂牧、Enumerable 特性

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

(function(){

varo?=?{};

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)建對象的屬性,則這個屬性的?enumerable?為?true

for(varitemino){//遍歷所有可枚舉屬性包括繼承的屬性

console.log(item);

}

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

console.log(o.propertyIsEnumerable('a'));//true

console.log(o.propertyIsEnumerable('b'));//false

console.log(o.propertyIsEnumerable('c'));//false

})();

輸出結(jié)果如下:

五侈净、Configurable 特性

(function(){

varo?=?{};

Object.defineProperty(o,"a",{get:function(){return1;},

configurable:false}?);

//enumerable?默認(rèn)為?false,

//value?默認(rèn)為?undefined,

//writable?默認(rèn)為?false,

//set?默認(rèn)為?undefined

//拋出異常,因為最開始定義了?configurable?為?false,故后期無法對其進(jìn)行再配置

Object.defineProperty(o,"a",{configurable:true}?);

//拋出異常,因為最開始定義了?configurable?為?false,故后期無法對其進(jìn)行再配置,enumerable?的原值為?false

Object.defineProperty(o,"a",{enumerable:true}?);

//拋出異常,因為最開始定義了?configurable?為?false,set的原值為?undefined

Object.defineProperty(o,"a",{set:function(val){}}?);

//拋出異常,因為最開始定義了?configurable?為?false,故無法進(jìn)行覆蓋,盡管想用一樣的來覆蓋

Object.defineProperty(o,"a",{get:function(){return1}});

//拋出異常,因為最開始定義了?configurable?為?false,故無法將其進(jìn)行重新配置把屬性描述符從存取描述符改為數(shù)據(jù)描述符

Object.defineProperty(o,"a",{value:12});

console.log(o.a);//輸出1

deleteo.a;//想要刪除屬性,將失敗

console.log(o.a);//輸出1

})();

六、提高及擴(kuò)展

1.屬性描述符中容易被誤導(dǎo)的地方之writable與configurable

(function(){

varo?=?{};

Object.defineProperties(o,{

"a":?{

value:1,

writable:true,//可寫

configurable:false//不可配置

//enumerable?默認(rèn)為?false?不可枚舉

},

"b":{

get:function(){

returnthis.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});//拋出異常,因為?configurable?為?false

})();

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

(function(){

varobj?=?{};

//回收同一對象,即減少內(nèi)存浪費

functionwithValue(value){

vard?=?withValue.d?||(

withValue.d?=?{

enumerable:false,

configurable:false,

writable:false,

value:null

}

);

d.value?=?value;

returnd;

}

Object.defineProperty(obj,"key",withValue("static"))

})();

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末溺忧,一起剝皮案震驚了整個濱河市咏连,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鲁森,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件振惰,死亡現(xiàn)場離奇詭異歌溉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)骑晶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門痛垛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人桶蛔,你說我怎么就攤上這事匙头。” “怎么了仔雷?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵蹂析,是天一觀的道長。 經(jīng)常有香客問我碟婆,道長电抚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任竖共,我火速辦了婚禮蝙叛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘公给。我一直安慰自己借帘,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布淌铐。 她就那樣靜靜地躺著肺然,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匣沼。 梳的紋絲不亂的頭發(fā)上狰挡,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼加叁。 笑死倦沧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的它匕。 我是一名探鬼主播展融,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼豫柬!你這毒婦竟也來了告希?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤烧给,失蹤者是張志新(化名)和其女友劉穎燕偶,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體础嫡,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡指么,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了榴鼎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伯诬。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖巫财,靈堂內(nèi)的尸體忽然破棺而出盗似,到底是詐尸還是另有隱情,我是刑警寧澤平项,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布赫舒,位于F島的核電站,受9級特大地震影響葵礼,放射性物質(zhì)發(fā)生泄漏号阿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一鸳粉、第九天 我趴在偏房一處隱蔽的房頂上張望扔涧。 院中可真熱鬧,春花似錦届谈、人聲如沸枯夜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽湖雹。三九已至,卻和暖如春曙搬,著一層夾襖步出監(jiān)牢的瞬間摔吏,已是汗流浹背鸽嫂。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留征讲,地道東北人据某。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像诗箍,于是被迫代替她去往敵國和親癣籽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容