[筆記] 3 種 JavaScript 物件屬性的特性

TC Liu
TC Liu
May 19, 2018 · 5 min read

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

TC Liu

Written by

TC Liu

👨‍💻 Frontend developer. 🕸️ Growing with the Web. 👪 Learning from open source and pure people.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade