對find的結果進行判空
const items = [
{
id: 1,
name: 'Ben',
age: 25,
},
{
id: 2,
name: 'Lily',
age: 20,
},
];
const targetItem = items.find((item) => item.age === 50);
console.log(targetItem.name);
// Error: Cannot read properties of undefined (reading 'name')
上面的程式碼中,我們在find
的返回值上直接訪問屬性,會有可能導致異常。
因為在沒有找到目標時,find
的返回值會是undefined
,在undefined
上訪問物件,就會丟擲異常。
所以,遵循簡單的策略,永遠對find
的返回值進行判空,避免意外情況。
const targetItem = items.find((item) => item.age === 50);
console.log(targetItem?.name);
// undefined
利用map與filter組合過濾
目標:
剔除users
不存在於permissions
中的使用者資料,並且將permissions
的codes
寫入users
。
// 使用者列表資料
const users = [
{
id: 1,
name: 'Ben',
age: 25,
codes: [],
},
{
id: 2,
name: 'Lily',
age: 20,
codes: [],
},
];
// 使用者的許可權code資料
const permissions = [
{
id: 1,
codes: ['create', 'delete'],
},
{
id: 3,
codes: ['create', 'delete'],
},
];
先給出一個符合直覺的版本
方案1:
- 遍歷
users
,檢查每個user
是否存在於permissions
,得到hasPermissonUsers
- 對上面的
hasPermissonUsers
進行遍歷,從permissions
中取出每個user
的codes
const adminUsers = users
.filter((user) => permissions.find((permission) => permission.id === user.id))
.map((user) => ({
...user,
codes: permissions.find((permission) => permission.id === user.id)?.codes ?? [],
}));
上面的程式碼很好的完成了任務,但是還有一點最佳化的空間。
在上面的程式碼中,filter
和map
內部都對permissions
進行了一次遍歷,有沒有辦法避免呢?
方案2:
- 遍歷
users
,獲取每個user
對應的permission
,將獲取到的permission.codes
存到當前user
中,將無匹配結果的資料作為null
返回 - 對
users
進行一次真假值檢查,即可過濾掉不存在於permissions
的使用者
const betterAdminUsers = users
.map((user) => {
// 用target來實現2個目的
const target = permissions.find((permission) => permission.id === user.id);
// 1 獲取permission中的codes
if (target) {
return {
...user,
codes: target.codes,
};
}
// 2 用於給後面的filter過濾掉不存在於permissions的使用者
return null;
})
.filter(Boolean);
方案2中,我們減少了一次find
查詢,而且程式碼變得更簡單了。
關鍵點就是,在map
內部,將本次對permissions
的查詢結果透過某種方式傳遞給了filter
,避免了filter
內部再次permissions
對進行查詢。
針對方案2的更新:
這種在map
裡面幹兩件事的程式碼,違反了單一職責,感覺沒有必要,增加了閱讀者的心智負擔。
這裡對方案1進行了一點小改造,這樣map
裡面保證了單一職責,它只做了資料轉存這一件事。然後filter
也只做了過濾這一件事。
const adminUsers = users
.map((user) => {
const target = permissions.find((permission) => permission.id === user.id);
return {
...user,
isHasPermission: !!target,
codes: target?.codes ?? [],
};
})
.filter((user) => user.isHasPermission);