這篇文章要介紹檢查物件裡是否存在某個屬性的三種方式。
1. 直接試著存取該屬性
第一方法非常簡單,那就是直接試著存取該屬性看看!若該屬性不存在於物件中,則會回傳 undefined。因此可以根據此特性來判斷某個屬性是否存在於物件當中。
const obj={
name: 'Justin',
age: 28,
birthday: '1994/03/01'
}
console.log(obj.name); // 'Justin'
console.log(obj.gender); // undefined
console.log(obj['age']); // 28
不過這個方法有個致命的缺點:當今天屬性的值原本就是 undefined 時,就會造成判斷錯誤。
2. 運算子 in
或者,也可以使用 JS 內建的運算子 in 來判斷屬性是否存在於物件當中。'propertyName' in obj
用來判斷屬性'propertyName'
是否存在於物件 obj 中,回傳 true 代表存在,false 則為不存在。
我們繼續沿用上個例子:
console.log('name' in obj); // true
console.log('gender' in obj); // false
3. Object.prototype.hasOwnProperty()
使用方法為 object.hasOwnProperty('propertyName')
,其效果與關鍵字 in
類似(為什麼說「類似」呢先賣個關子)。
console.log(Object.hasOwnProperty('name')); // true
console.log(Object.hasOwnProperty('gender')); // false
in 與 hasOwnProperty()
從上面的例子來看,這兩個的的功能一模一樣。但其實它們有個很大的不同點,而這是從上面的例子看不出來的。
in
會沿著原型鏈往上爬,沿路檢查是否有該屬性。而hasOwnProperty()
則只會檢查物件「本身」是否含有該屬性。
舉一個全新的例子 🌰
const animal = {
sleep() {
console.log('Zzzz...');
},
};
const pet = {
name: 'Judy',
age: 2,
type: 'dog',
greet() {
console.log('WOOF!WOOF!');
},
};
// 透過 setPrototypeOf()來指定物件與物件之間的原型關係。
Object.setPrototypeOf(pet, animal);
// Object.setPrototypeOf(pet, animal) 將會把物件 animal 指定作為物件 pet 的原型。
先把 pet 印出來看看!
console.log(pet);
這張圖片的重點在物件 pet 內有個叫做 [[prototype]] 的屬性!
然後這個 [[prototype]] 屬性是用來指向 pet 物件的原型(也就是我們剛剛手動設定的物件 animal),所以你可以看到 sleep method 就在裡面。
因此,如果你透過物件 pet 來呼叫 sleep 是沒問題的喔~請看
pet.sleep(); // Zzzz...
💌 溫馨小叮嚀:我們是無法直接存取這個 [[prototype]] 屬性的,因為它屬於內部屬性。
好了,一切我們必要的東西都已經設定完畢!現在就可來測試看看 in 和 hasOwnProperty() 的不同之處。
console.log(pet.hasOwnProperty('sleep')); // false
console.log('sleep' in pet); // true
太好了!
結果跟與我們的期待相符 ☺️
因為 sleep method 並不直接存在於物件 pet 裡,因此 hasOwnProperty
會回傳 false。而 in
則會幫我們沿著原型鏈一路網上尋找,如果成功找到就會回傳 true
,而在這個例子當中,in 的確找到了 sleep method!
同場加應:Object.hasOwn()
寫到一個段落的時候,看到 PJCHEN der 的這部 YouTube 影片,才知道原來還有一個酷東西叫做 Object.hasOwn()
。
hasOwn() 的功用和 hasOwnProperty 基本上是一樣的,都是用來檢查特定屬性是否直接存在於物件當中,使用方式稍稍不同: Object.hasOwn(obj, 'propertyName')
。
最最最重要的是,MDN 推薦大家用 hasOwn() 取代 hasOwnProperty()。原因有幾個:
1. hasOwnProperty() 會被覆寫
當今天你要檢查的物件內剛好有一個屬性叫做 hasOwnProperty(),那麼當你試著呼叫 hasOwnProperty() 時,會直接執行你在物件內自己定義的內容,而不會執行判斷屬性是否存在的內建功能。
const foo = {
hasOwnProperty() {
return false;
},
bar: 'The dragons be out of office',
};
foo.hasOwnProperty('bar'); //false,因為已經被 foo 裡面的 hasOwnProperty 覆蓋
Object.hasOwn(foo, 'bar'); //true,正常發揮!
MDN 還舉了一個例子,那就是當我們使用 Object.create(null) 來創造一個乾淨的空物件時(乾淨指的是它並沒有繼承 Object.prototype 裡面的屬性和方法),無法使用 hasOwnProperty!
const foo = Object.create(null);
foo.hasOwnProperty('foo');
//Uncaught TypeError: foo.hasOwnProperty is not a function
Object.hasOwn(foo, 'prop'); // true,正常發揮!
之所以 hasOwn 都能正常運作是因為 hasOwn 這個方法就直接存在於 Object 內,但是 hasOwnProperty 則是被定義在 Object.prototype 裡。
參考資料
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn