物件屬性取值
31 Oct 2019本文探討物件屬性取值可能會遇到的兩件事與其解法
- 取不到值時的後續處理?
- 屬性的名稱用點
.
分隔,要怎麼取值?
取不到值時的後續處理
物件屬性取值時,若取不到值而得到 undefined,要怎麼給定預設值?
情境如下,物件 people 使用 ES6 解構
const people = {
name: 'Nina',
age: '25',
family: {
father: 'David',
mother: 'Jenny',
brother: 'Nick',
sister: 'Anna'
},
};
const { family: { grandFather } } = people;
console.log(`grandFather: ${grandFather}`); // 取不到值,得到 undefined
其中 grandFather 被解構和宣告,但物件 people 沒有對應屬性,因此取不到值,得到 undefined。
解法 1:Lodash 的 _.get
使用 Lodash 的 _.get
取值,即可在第三個參數設定預設值,避免得到 undefined 的狀況。
const grandFather = _.get(people, 'family.grandFather', 'John');
console.log(`grandFather: ${grandFather}`); // "grandFather: John"
解法 2:Optional Chaining
關於檢視物件中是否存在某屬性,再依照存在與否回傳值或 undefined,可用 Optional Chaining,但目前只是實驗功能,需要搭配 babel 才能使用。
如下,dogName 照理說應該直接報錯「Uncaught TypeError: Cannot read property ‘name’ of undefined」,但得到 undefined;rabbitName 由於也是得到 undefined,因此可利用 ||
來設定初始值,再得到 Nina。
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah'
}
};
const dogName = adventurer.dog?.name;
console.log(dogName); // undefined
const rabbitName = adventurer.rabbit?.name || 'Nina';
console.log(rabbitName); // Nina
ReferenceError vs undefined
ReferenceError 和 undefined 這兩者的差異
- ReferenceError 是指未宣告為變數卻企圖存取所造成的錯誤。
- undefined 表示變數已宣告,但沒有賦值。
範例。
var a;
console.log(`a: ${a}`); // a: undefined
console.log(`b: ${b}`); // ReferenceError: b is not defined
比較常見的發生狀況是…「沒取到」與「以為取到」的 undefined 和 ReferenceError…滿多 腦殘的 人都會誤將存在的屬性當成有宣告的變數在用,出錯了還不知道發生事 (  ̄ 3  ̄)y▂ξ
const people = {
name: 'Nina',
age: '25',
family: {
father: 'David',
mother: 'Jenny',
brother: 'Nick',
sister: 'Anna'
},
};
const { family: { grandFather } } = people;
console.log(`grandFather: ${grandFather}`); // 取不到值,得到 undefined
console.log(`brother: ${brother}`); // ReferenceError: brother is not defined
其中
- grandFather 有被解構和宣告,但物件 people 沒有對應屬性,因此取不到值,得到 undefined。
- brother 沒有做解構,因此沒有被宣告為一個變數,得到 ReferenceError。
屬性的名稱用點 .
分隔,要怎麼取值
eat.snack
是一個屬性的名稱,但由於中間用點隔開,因此無法被正確解構。
const people = {
name: 'Nina',
age: '25',
family: {
father: 'David',
mother: 'Jenny',
brother: 'Nick',
sister: 'Anna'
},
'eat.snack': 'cake',
};
const { eat.snack } = people; // Uncaught SyntaxError: Unexpected token '.'
解法 1:陣列
使用陣列且 key 放字串的方式處理。
people['eat.snack']; // 'cake'
解法 2:Lodash 的 _.get
使用 Lodash 的 _.get
取值。
如下,將 eat.snack
這個屬性名稱放入第二個 path 參數即可。
const people = {
name: 'Nina',
age: '25',
family: {
father: 'David',
mother: 'Jenny',
brother: 'Nick',
sister: 'Anna',
},
'eat.snack': 'cake',
};
const eatSnack = _.get(people, 'eat.snack');
console.log(`eatSnack: ${eatSnack}`); // "eatSnack: cake"
但 _.get
對於屬性用點分隔的方式,僅可查找指定到的當層而已,若是下一層或多層就會找不到。
const people = {
// 略
eat: {
'eat.snack': 'cake',
eat: {
snack: 'not this cake',
},
},
};
const eatSnack = _.get(people, 'eat.eat.snack'); // 找不到,以為路徑是 eat > eat > snack
console.log(`eatSnack: ${eatSnack}`); // "not this cake"
總結 _.get
比起 ES6 原生的解構來說,優點是
- 可設定預設值,避免傳入的物件沒有對應的屬性而取到 undefined,造成後續程式出錯,這在無法預期傳入物件內容時尤其有用。
- 當屬性名有點
.
的時候可被正確解析,但只限於指定到的當層。