Object.keys() ??? Object.getOwnPropertyNames() ???
到底有哪些相同之處?什麼時候該用哪個呢?’for (let x of data)’ ? ‘for (let x in data)’ ?搞得我好亂啊
🤔🤔🤔
很多時候,我們對物件屬性做 新增,修改,刪除,
都是靠直覺又方便的『dot 和 delete 大法』,像這樣:
let person = { name: 'derek' };person.name; // READ
person.age = 28; // CREATE
person.name = 'DEREK'; // UPDATE
delete person.age; // DELETE
你像個園丁一樣,輕鬆的對物件這邊修,那邊剪。
但你可能很少聽說,這都是靠著屬性內部有更細緻的『特性』:
- 💡Enumerable: 讓你可以用
Object.keys(person)
將他們『列舉』出來 (READ) - 💡Writable: 讓你可以對屬性做『修改』(UPDATE)
- 💡Configurable: 讓你有權限調整某屬性的上述兩個特性。此外也讓你可以用
delete
來移除某屬性(DELETE)
也就是說,預設情況下這些屬性的『三大特性』設定被打開了,才讓你可以如此輕鬆操作。如果要修改三大特性請看 Object.defineProperty() 。
回到文章開頭的問題,其實 Object.keys() 和 Object.getOwnPropertyNames() 的差異就在於:
Object.keys(x) 只會列出 x 自身的 Enumerable (可列舉的) 的屬性,而 Object.getOwnPropertyNames(x) 列出更多,x 身上不可列舉的屬性也包含在內
一般來說我們關注的屬性常是可列舉的,所以開發上常用 Object.keys() 來遍歷。如果你用了 Object.getOwnPropertyNames() 可能會得到更多非預期的隱藏屬性。
let person = { name: 'derek' };Object.defineProperty(person, 'age', { enumerable: false });
person.age = 28;console.log(Object.keys(person)); // [ 'name' ]
console.log(Object.getOwnPropertyNames(person)); // [ 'name', 'age']
而常見的 JSON.stringify()
也只會輸出物件的可列舉屬性。
常見的 for(let x in person)
也只會輸出物件的可列舉屬性。
console.log(JSON.stringify(person)); // {"name":"derek"}
for (let x in person) console.log(x); // 'name'
有時會和朋友聊到混淆的語法,像是for (let x in person)
和for (let person of persons)
。我自己喜歡這樣記,比較不會混淆:
- 中文『你們當中的一群人』,英文翻譯是
one of you guys
in
有表示內部的意思,適合用在物件屬性。
JS 另外還有語法'name' in person
來檢查屬性是否存在於
該物件或原型鍊身上。
最後,整理一張自己常混淆的語法,以及其對應的屬性的『特性』:
| 語法 | Enumerable ONLY? | 不包含原型鍊? |
|:----------------------------:|------------------|---------------|
| Object.keys() | ✔️ | 不包含 |
| Object.getOwnPropertyNames() | no | 不包含 |
| for (let x in person) | ✔️ | 包含 |
| 'name' in person | no | 包含 |
後記(Jun 8. 2018):發佈這篇文章後,恰好關注了 #SmooshGate 事件。
EcmaScript 新標準草案中的 Array.prototype.flatten
函式會讓舊網頁壞掉的原因,正是因為函式庫 MooTools 直接修改了原型鍊,導致在 for (... in ...)
語法中無法取得『預期為可列舉的 flatten』。這也導致 tc39 委員會考慮將 flatten
改名為 flat
。
想了解詳細過程以及此事件引起的討論,請看 #SmooshGate FAQ (翻譯版)以及 SmooshGate: The ongoing struggle between progress and stability in JavaScript。