JavaScript的對象屬性(properties) 是可枚舉恩袱、可寫、和可配置的

經(jīng)常有童鞋在碰到會困惑于JavaScript的對象屬性的(properties)的特性(attribute不過文中多次以屬性properties胶哲,也就是屬性的屬性出現(xiàn)畔塔,只過個人覺得這么叫容易引起困惑)問題,看到國外有網(wǎng)友很形象地分析了鸯屿,很值得細品與分享澈吨,遂譯。如題寄摆,Javascript屬性(properties) 是可枚舉谅辣、可寫、和可配置的婶恼,我們用得最多的屬性的一個特性是value桑阶,基余的幾個分別是enumerable, writable and configurable。

對象Objects是Javascript最重要的一個部分勾邦, JS的對象語法非常的簡潔易用蚣录,所以我們可以毫不費力地不斷地建立和使用他們。

下面是關(guān)于 JS 對象Objects的基本用法:

<pre>
// My beloved object ob
var ob = {a: 1};

// Accessing to a property
ob.a; // => 1

// Modifying the value of a property
ob.a = 0;
ob.a; // => 0;

// Creating a new property
ob.b = 2;
ob.b; // => 2

// Deleting a property
delete ob.b;
ob.b; // => undefined
</pre>

但是, 你是否同時也知道上述例子中所有的對象屬性(object properties)是可枚舉检痰、可寫和可配置的呢包归?我的意思是:

  • value(值):這里是我們經(jīng)常用到的——給對象的屬性賦值
  • Enumerable(可枚舉): 我可以使用for..in循環(huán)訪問所有的屬性, 同時,一個對象的可枚舉屬性的鍵值返回所使用的是Object.keys方法
  • Writable(可寫): 我可以修改它們的值,我能更新一個屬性property公壤,僅僅只需分配一個新值給它换可,如:ob.a = 1000
  • Configurable(可配置): 我可以修改一個屬性的表現(xiàn)behavior,因此厦幅,我可以使得他們變成不可枚舉(non-enumerable)沾鳄,不可寫(non-writable)甚至不可配置(non-cofigurable),如果我覺得有必要這么做的話确憨∫胲瘢可配置屬性(Configurable properties)是使用delete操作時唯一能被刪除的。

我敢打賭休弃,你應該已經(jīng)知道對象屬性的前三個特征吞歼,但是只有很少的開發(fā)者知道他們可以使用對象(Object)的一個被稱為defineProperty的方法,來建立和更新這些對象屬性為不可枚舉(non-enumerable) 或不可變更塔猾。

<pre>
// Adding a property to ob using Object.defineProperty
Object.defineProperty( ob, 'c', {
value: 3,
enumerable: false,
writable: false,
configurable: false
});

ob.c; // => 3

Object.getOwnPropertyDescriptor( ob, 'c' );
// => {value: 3, enumerable: false, writable: false, configurable: false}
</pre>

我個人覺得這種語法相比我們常用的其它命令來說算不上友好篙骡,但是,擁有這類屬性對于某些特定目的來說可以說是真的很方便,定義對象(Object)的屬性被稱為描述符(descriptor)丈甸,而你則可以使用Object.getOwnPropertyDescriptor方法來看一看任何屬性的描述符糯俗。

有趣的是,對于那一類已經(jīng)配置的對象來說睦擂,當使用Object.defineProperty分配并添加一個屬性的時候得湘,對象屬性的默認選項相關(guān)值是完全相反的:
屬性property默認指定的設置為不可枚舉(non-enumerable)、不可寫(non-writable)顿仇、不可配置(non-configurable)淘正。

<pre>
// The 'f' property will be non-enumerable. non-writable and non-configurable
Object.defineProperty( ob, 'f', {value: 6} );
</pre>

如果你使用Objet.create(prototype,properties)實例化對象的話,在對象建立時定義對象屬性同樣是可以的夺欲。它接收一個對象的屬性描述符作為第二個參數(shù)跪帝,一般可以按如下方式使用:

<pre>
var ob = Object.create(Object.prototype, {
a: { writable:true, enumerable:true, value: 1 },
b: { enumerable: true, value: 2 }
}});

ob; // => {a:1, b:2}
</pre>

對象的不可枚舉屬性non-enumerable properties

就像我之前說的,枚舉屬性指的是可否使用for...in循環(huán)來訪問些阅,因此不可枚舉non-enumerable的屬性就不支持伞剑。基本上講市埋,在使用大多數(shù)的函數(shù)來把對象作為hashmaps來處理的時,不可枚舉屬性是不可用的黎泣。

  • 他們不可用于for..in循環(huán)
  • 在使用Object.keys函數(shù)時,他們不會出現(xiàn)
  • 當使用JSON.stringify時缤谎,他們不會系列序列化(serialized)

因此抒倚,他們是屬于一類秘密的變量, 但你還是能夠直接地訪問到他們。

<pre>
var ob = {a:1, b:2};

ob.c = 3;
Object.defineProperty(ob, 'd', {
value: 4,
enumerable: false
});

ob.d;
//=> 4你可以直接地訪問到他們的value值

for( var key in ob ) console.log( ob[key] );
// Console will print out他們不可用于for..in循環(huán)
// 1
// 2
// 3

Object.keys( ob );
// => ["a", "b", "c"]在使用Object.keys函數(shù)時坷澡,他們不會出現(xiàn)

JSON.stringify( ob ); // => "{a:1,b:2,c:3}"

ob.d;
// => 4當使用JSON.stringify時托呕,他們不會系列序列化(serialized)
</pre>

基于對像屬性的這一類屬性(properties或特性attribute)不會被序列化(serialize),我發(fā)現(xiàn)他們真的是非常非常的好用,在我需要處理對象數(shù)據(jù)模型時(data model objects)项郊,因為我可以使用不可枚舉特性(屬性)添加處理信息到他們馅扣。

注:其實這里的屬性個人覺得可以按W3CSchools上面的稱為attribute比較合適,畢竟他們不屬于標準的property屬性着降。

<pre>
// 假定這個model描繪了一輛汽車,他有一個引用reference到他自身
// reference to its owner using owner's id in the owner attribute

var car = {
id: 123,
color: red,
owner: 12
};

// I also have fetched the owner from the DB
// Of course, the car is mine :)
var owner = {
id: 12,
name: Javi
}

// I can add the owner data to the car model
// with a non-enumerable property, maybe it can
// be useful in the future
Object.defineProperty( car, 'ownerOb', {value: owner} );

// I need the owner data now
car.ownerOb; // => {id:12, name:Javi}

// But if I serialize the car object, I can't see me
JSON.stringify( car ); // => '{id: 123, color: "red", owner: 12}'
</pre>

你能想像這對于建立一個如上例中的 ORM 庫(ORM library)是多么有用嗎差油?

在這個案例中你需要知道一個對象中的所有屬性properties,可枚舉和不可枚舉的每一個屬性任洞,Object.getOwnPropertyNames方法就可以返回一個由所有的鍵名names組成的數(shù)組蓄喇。

Object’s non-writable properties

While the world waits for ES6 to finally arrive with the desired const statement, non-writable properties are the most similar thing to a constant that we have in Javascript. Once its value is defined, it is not possible to change it using assignments.

<pre>
var ob = {a: 1};

Object.defineProperty( ob, 'B', {value: 2, writable:false} );

ob.B; // => 2

ob.B = 10;

ob.B; // => 2
</pre>

As you can see, the assignment didn’t affect the value of ob.B property. You need to be careful, because the assignment always returns the value assigned, even if the property is non-writable like the one in the example. In strict mode, trying to modifying a non-writable property would throw an TypeError exception:

<pre>
var ob = {a: 1};
Object.defineProperty( ob, 'B', {value: 2, writable:false} );

// Assingments returns the value
ob.B = 6; // => 6
ob.B = 1000; // => 1000

// But the property remains the same
ob.B; => 2;

function updateB(){
'use strict';
ob.B = 4; // This would throw an exception
}

updateB(); // Throws the exception. I told you.
</pre>

It is also needed to keep in mind that if the non-writable property contains an object, the reference to the object is what is not writable, but the object itself can be modified yet:

<pre>
var ob = {a: 1};
Object.defineProperty( ob, 'OB', {value: {c:3}, writable:false} );

ob.OB.c = 4;
ob.OB.d = 5;

ob.OB; // => {c:4, d:5}

ob.OB = 'hola';

ob.OB; // => {c:4, d:5}
</pre>

If you want to have a property with an completely non-writable object, you can use the function Object.freeze. freeze will make impossible to add, delete or update any object’s property, and you will get a TypeError if you try so in strict mode.

<pre>
var ob = { a: 1, b: 2 };

ob.c = 3;

// Freeze!
Object.freeze( ob ); // => {a:1,b:2,c:3}

ob.d = 4;
ob.a = -10;
delete ob.b;

Object.defineProperty( 'ob', 'e', {value: 5} );

// Every modification was ignored
ob; // => {a:1,b:2,c:3}
</pre>

Object’s non-configurable properties

You can update the previous behaviors of the properties if they are defined as configurable. You can use defineProperty once and again to change the property to writable or to non-enumerable. But once you have defined the property as non-configurable, there is only one behaviour you can change: If the property is writable, you can convert it to non-writable. Any other try of definition update will fail throwing a TypeError.

<pre>
var ob = {};
Object.defineProperty( ob, 'a', {configurable:false, writable:true} );

Object.defineProperty(ob, 'a', { enumerable: true }); // throws a TypeError
Object.defineProperty(ob, 'a', { value: 12 }); // throws a TypeError
Object.defineProperty(ob, 'a', { writable: false }); // This is allowed!!
Object.defineProperty(ob, 'a', { writable: true }); // throws a TypeError
</pre>

An important thing to know about the non-configurable properties is that they can’t be removed from the object using the operator delete. So if you create a property non-configurable and non-writable you have a frozen property.
<pre>
var ob = {};

Object.defineProperty( ob, 'a', {configurable: true, value: 1} );

ob; // => {a:1}
delete ob.a; // => true
ob; // => {}

Object.defineProperty( ob, 'a', {configurable: false, value: 1} );

ob; // => {a:1}
delete ob.a; // => false
ob; // => {a:1}
</pre>

總結(jié):

Object.defineProperty 在ES5時被引入, 你可以現(xiàn)在立刻就使用它,一般所有的主流瀏覽器都支持交掏,包括IE 9 (甚至IE 8也支持妆偏,但僅限于DOM對象。用一種與平常不同的方式來使用JavaScript的基本用法耀销,這通常是非常用趣的楼眷,而且它是非常易學的新東西僅僅只需要觀察JS的核心對象是如何開展工作的。
Object.defineProperty同樣給了我們一個機會來為對象的屬性建立個性定制(getters and setters)熊尉,但是關(guān)于這方面我今天不會寫,如果你對此感興趣或想了解更多參看amazing Mozilla的文檔掌腰。

譯自:http://arqex.com/967/javascript-properties-enumerable-writable-configurable

Tag:ECMAScript2015, ES6, JavaScript
發(fā)布時間:2015年08月25日
博客被黑狰住,挪窩簡書安家……

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市齿梁,隨后出現(xiàn)的幾起案子催植,更是在濱河造成了極大的恐慌,老刑警劉巖勺择,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件创南,死亡現(xiàn)場離奇詭異,居然都是意外死亡省核,警方通過查閱死者的電腦和手機稿辙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來气忠,“玉大人邻储,你說我怎么就攤上這事【稍耄” “怎么了吨娜?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長淘钟。 經(jīng)常有香客問我宦赠,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任勾扭,我火速辦了婚禮缤骨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘尺借。我一直安慰自己绊起,他們只是感情好,可當我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布燎斩。 她就那樣靜靜地躺著虱歪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪栅表。 梳的紋絲不亂的頭發(fā)上笋鄙,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天,我揣著相機與錄音怪瓶,去河邊找鬼萧落。 笑死,一個胖子當著我的面吹牛洗贰,可吹牛的內(nèi)容都是我干的找岖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼敛滋,長吁一口氣:“原來是場噩夢啊……” “哼许布!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起绎晃,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蜜唾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后庶艾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體袁余,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年咱揍,在試婚紗的時候發(fā)現(xiàn)自己被綠了颖榜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡述召,死狀恐怖朱转,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情积暖,我是刑警寧澤藤为,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站夺刑,受9級特大地震影響缅疟,放射性物質(zhì)發(fā)生泄漏分别。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一存淫、第九天 我趴在偏房一處隱蔽的房頂上張望耘斩。 院中可真熱鬧,春花似錦桅咆、人聲如沸括授。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荚虚。三九已至,卻和暖如春籍茧,著一層夾襖步出監(jiān)牢的瞬間版述,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工寞冯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留渴析,地道東北人。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓吮龄,卻偏偏與公主長得像俭茧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子螟蝙,可洞房花燭夜當晚...
    茶點故事閱讀 44,947評論 2 355

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