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

TC Liu
5 min readMay 19, 2018

--

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

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