可枚舉性(enumerable)用來控制所描述的屬性,是否將被包括在for...in循環之中。具體來說,如果一個屬性的enumerable為false,下面三個操作不會取到該屬性。
* for..in循環 :只遍歷對象自身的和繼承的可枚舉的屬性
* Object.keys方法 :返回對象自身的所有可枚舉的屬性的鍵名
* JSON.stringify方法:只串行化對象自身的可枚舉的屬性
* Object.assign()(ES6):只拷貝對象自身的可枚舉的屬性
這四個操作之中,只有for...in
會返回繼承的屬性。至於for...in
循環和Object.keys
方法的區別,在於前者包括對象繼承自原型對象的
屬性,而后者只包括對象本身的
屬性。如果需要獲取對象自身的所有屬性,不管enumerable的值,可以使用Object.getOwnPropertyNames
方法
例子:
var o = {a:1, b:2}; o.c = 3; Object.defineProperty(o, 'd', { value: 4, enumerable:
false }); o.d
//
4 for( var key in o ) console.log( o[key] ); // 遍歷獲取對象的屬性值 //
1
//
2 // 3 Object.keys(o) // ["a", "b", "c"] (獲取對象的屬性名) JSON.stringify(o) "{a:1,b:2,c:3}" (把對象轉換成為字符串)
上面代碼中,d屬性的enumerable為false,所以一般的遍歷操作都無法獲取該屬性,使得它有點像“秘密”屬性,但還是可以直接獲取它的值。
實際上,引入enumerable
的最初目的,就是讓某些屬性可以規避掉for...in
操作。比如,對象原型的toString
方法,以及數組的length
屬性,就通過這種手段,不會被for...in
遍歷到。
Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable // false Object.getOwnPropertyDescriptor([], 'length').enumerable // false
上面代碼中,
toString
和length
屬性的enumerable
都是false
,因此for...in
不會遍歷到這兩個繼承自原型的屬性。
另外,ES6規定,所有Class的原型的方法都是不可枚舉的。
Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, 'foo').enumerable // false
總的來說,操作中引入繼承的屬性會讓問題復雜化,大多數時候,我們只關心對象自身的屬性。所以,盡量不要用
for...in
循環,而用Object.keys()
代替。