《你不知道的JavaScript》之對象二

接下來繼續(xù)討論對象的主要內(nèi)容

一、屬性描述符

對于對象中的屬性,我們一般都是直接調(diào)用,但是屬性本身又有什么特性呢,該怎么去描述?屬性描述符就扮演了這樣一種角色。屬性描述符是在ES5以后才有的,看下面的代碼。


? var myobjec = {

? ? ? a:2,

? ? ? };

? ? ? var descriptor = Object.getOwnPropertyDescriptor(myobjec,"a")

? ? ? console.log(descriptor);

? ? ? //返回的結(jié)果為一個object對象:

{

configurable:true

enumerable:true

value:2

writable:true

}


返回的對象中包含了四個描述符:configurable(可配置)、enumerable(可枚舉)、value(值)、writable(可寫入)。

這些屬性描述符可以修改嗎?當(dāng)然,我們可以用Object.defineProperty(...)來添加一個新的屬性或是修改一個已有屬性。

1)writable

決定了屬性是否可以被修改。如果將其設(shè)置為false,那么對應(yīng)的value是不能被修改的。



? ? ? var myobject = {

? ? ? ? ? a:2,

? ? ? };

? ? ? Object.defineProperty(myobject,"a",{

? ? ? writable:false,

? ? ? configurable:true,

? ? ? enumerable:true,

? ? ? value:2

? ? ? })

? ? ? myobject.a = 4;

? ? ? console.log(myobject.a);//2


2)configurable(可配置)

只要是可配置,就可以用defineProperty來修改屬性描述符。


? ? ? var myobject = {

? ? ? ? ?a:2,

? ? ? };

? ? ? myobject.a = 3;

? ? ? console.log(myobject.a ); //3

? ? ? Object.defineProperty(myobject,"a",{

? ? ? writable:true,

? ? ? configurable:false,

? ? ? enumerable:true,

? ? ? value:4

? ? ? });

? ? ? console.log(myobject.a);//4

? ? ? myobject.a = 5;

? ? ? console.log(myobject.a);//5

? ? ? Object.defineProperty(myobject,"a",{

? ? ? writable:false,

? ? ? configurable:false,

? ? ? enumerable:true,

? ? ? value:6

? ? ? });? //Uncaught TypeError


如果將configurable設(shè)置為false后,再去配置就會報“未捕獲類型”錯誤。

3)enumerable(可枚舉)

通常屬性的這個描述符默認(rèn)為true,比如在for循環(huán)中,便可以枚舉此屬性。如果你在循環(huán)遍歷中不想讓該屬性出現(xiàn),那么將它的configurable設(shè)置為false即可。

二、屬性不可變性

很多時候,你都希望屬性是不可變的,在ES5中可以通過很多方法來實現(xiàn):

1)將屬性描述符writable和configurable設(shè)置為false即可;

2)禁用:可以使用Object.preventExtensions(..)來禁止一個對象添加新屬性并且保留已有屬性;


? ? var myobject = {

? ? ? ?a:2,

? ? ? };

? ? ? Object.preventExtensions(myobject);

? ? ? myobject.b = 3;

? ? ? console.log(myobject.b);//undefined


3)密封:Object.seal(...),調(diào)用這個方法時會調(diào)用preventExtention,并把所有的屬性都標(biāo)記為configurable:false,什么意思呢?就是說調(diào)用密封方法后,任何為對象添加、刪除新屬性的操作都是不允許的,但是屬性值可以被修改,

4)凍結(jié):Object.freeze(),這個方法會調(diào)用seal方法,同時將writable標(biāo)記為false,所以這個不能修改的級別就比較高了,不僅不能添加刪除,而且也不能修改了。

三、[[get]] 和? [[put]]操作

在訪問對象屬性時,表面上我們只是獲取了屬性值這么簡單,其實是在對象上進(jìn)行了[[get]]操作,對象的內(nèi)置方法 [[get]] 會查找對象中是否存在改屬性,如果存在返回屬性對應(yīng)的值,如果不存在,其實會執(zhí)行另外一種行為,就是查找[[ prototype ]]鏈,也就是原型鏈,這個后面會講到。

如果無論如何都找不到這個屬性,那么就會返回undefined。


? ? ? var myobject = {

? ? ? a:2,

? ? ? };

? ? ? console.log(myobject.b);//undefined

? ? ? console.log(c); //Uncaught ReferenceError: c is not defined


注意屬性訪問和變量訪問的區(qū)別,如果對象中不存在屬性,那么返回undefined,而變量在當(dāng)前作用域中不存在的話,就會拋出 referenceError錯誤。原因就是屬性訪問調(diào)用了對象內(nèi)置操作[[get]]。

對于[[put]]操作,你可能認(rèn)為一般是在屬性賦值時被調(diào)用,但實際情況并不完全這樣,觸發(fā)的原因有很多。不過首先要看對象中是否存在這個屬性,如果存在的話,那么一般會檢查下面的內(nèi)容:

1)屬性是否是屬性描述符,如果是并且存在setter,就會調(diào)用setter,什么是setter呢,接下來會講到;

2)屬性描述符writable是否是false,如果是的話,在非嚴(yán)格模式下靜默失敗,在嚴(yán)格模式下拋出typeError錯誤;

3)如果上述情況都不是,那么將該值設(shè)置為屬性值。

如果對象中不存在這個屬性,那么[[put]]操作會查找原型鏈,這個后面會講到。

四、getter 和? setter 操作

ES5中的getter和setter操作會改變對象屬性的默認(rèn)操作,但是只能應(yīng)用在單個屬性上而不是整個對象上。有的同學(xué)會問到,平時好像沒有看到這兩個方法?。窟@是因為它們都是隱藏函數(shù),都是在屬性的獲取和賦值時默默的調(diào)用的。

看下面這段代碼:


var myobject = {

? ? ? get a(){

? ? ? return 2;

? ? ? }

? ? ? };

? ? ? console.log(myobject.a);//2

? ? ? Object.defineProperty(myobject,'b',{

? ? ? get:function(){

? ? ? return this.a*2;

? ? ? }

? ? ? })

? ? ? console.log(myobject.b);//4


上面兩種定義getter的方法都使得在訪問屬性時調(diào)用了getter。不過既然有了getter,那么setter也不能少對吧。


var myobject = {

? ? ? get a(){

? ? ? ? ? ?return this._a;

? ? ? },

? ? ? set a(val){?

? ? ? ? ? ? this._a = val*2;

? ? ? ? ? ?}

? ? ? };? ?

? ? ? myobject.a = 2;

? ? ? console.log(myobject.a); //4


到此為止,同上篇文章一起對對象的一些基本屬性做了系列的討論和講解,相信勤奮好學(xué)的同學(xué)們有了更深刻的認(rèn)識吧。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 來自:參 考 原 文 對象是由多個名/值對組成的無序的集...
    wyude閱讀 1,345評論 1 7
  • 對象 對象可以通過兩種形式定義: 聲明形式和構(gòu)造形式 聲明形式語法: var myObj = {key:value...
    qhaobaba閱讀 372評論 0 0
  • 盡管javascript里有大量內(nèi)建引用對象,很可能你還說會頻繁創(chuàng)建自己的對象。當(dāng)你在這么做的時候,記得javas...
    WanLum閱讀 594評論 1 3
  • 標(biāo)簽: js 還有原型鏈要更新呀 作用域 作用域是查找變量的一套規(guī)則 如果查找的目的是對變量進(jìn)行賦值,則進(jìn)行LH...
    一顆板栗_閱讀 730評論 0 0
  • 函數(shù)和對象 1、函數(shù) 1.1 函數(shù)概述 函數(shù)對于任何一門語言來說都是核心的概念。通過函數(shù)可以封裝任意多條語句,而且...
    道無虛閱讀 4,943評論 0 5

友情鏈接更多精彩內(nèi)容