Source:Here’s how you can make better use of JavaScript arrays
快速閱讀,我保證。過去幾個月裡,我注意我檢查過的pull requests仍然存在相同的四個錯誤,我貼這篇文章也是因為我自己犯了這些錯誤!讓我們瀏覽這些問題確保我們正確使用Array方法。
「如果你在陣列中尋找一些東西,請使用Array.indexOf。」我記得在學習JavaScript的過程中讀過這樣一句話。 這句話是真的,不用懷疑!
MDN文件說Array.indexOf返回找到的元素的第一個索引,因此如果稍後我們在程式碼中使用返回索引Array.indexOf就是解決方案。
但是如果我們只需要知道我們的陣列是否包含某值呢?這是一個是/否的問題,一個boolean問題。這種情況我建議使用返回boolean的Array.includes。
'use strict';
const characters = [
'ironman',
'black_widow',
'hulk',
'captain_america',
'hulk',
'thor',
];
console.log(characters.indexOf('hulk'));
// 2
console.log(characters.indexOf('batman'));
// -1
console.log(characters.includes('hulk'));
// true
console.log(characters.includes('batman'));
// false
Array.filter是一個非常有用的方法。它存另一個陣列創建一個所有項目的通過回調參數的新陣列。正如其名,我們必須使用此方法進行過濾並得到更短的陣列。
但是,假如我們知道我們的回調函數只返回一個項目,我就不推薦它 — 例如,使用回調函數透過唯一的ID過濾。這種情況下,Array.filter返回一個只有一個項目的陣列。尋找特定ID,我們的意圖可能是使用這個陣列所包含的唯一的值,這個陣列是沒有用的。
談論性能。返回所有符合回調函數的項目,Array.filter必須瀏覽整個陣列。而且,我們假設有幾百個項目符合我們的回調函數,我們過濾的陣列是非常大的。
避免這種情況,我建議使用Array.find。它需要像Array.filter一樣的回調函數,並返回滿足條件的第一個元素。而且只要一滿足條件,Array.find就會停止,無需瀏覽整個陣列。此外,通過Array.find尋找項目,我們可以更清楚了解我們的意圖。
'use strict';
const characters = [
{ id: 1, name: 'ironman' },
{ id: 2, name: 'black_widow' },
{ id: 3, name: 'captain_america' },
{ id: 4, name: 'captain_america' },
];
function getCharacter(name) {
return character => character.name === name;
}
console.log(characters.filter(getCharacter('captain_america')));
// [
// { id: 3, name: 'captain_america' },
// { id: 4, name: 'captain_america' },
// ]
console.log(characters.find(getCharacter('captain_america')));
// { id: 3, name: 'captain_america' }
我承認我犯過很多次這個錯誤。一個善良的朋友告訴我MDN文件可以找到更好的方法。這件事情跟上面的Array.indexOf / Array.includes案例很像。
上一個案例,Array.find需要一個回調參數並返回一個元素。假如我們需要知道我們的陣列是否包含值,Array.find是最好的解決方案嗎?可能不是,因為它返回一個值而不是boolean。
這種情況我建議使用Array.some,它返回boolean。另外在語義上,使用Array.some凸顯我們不需要找到項目。
'use strict';
const characters = [
{ id: 1, name: 'ironman', env: 'marvel' },
{ id: 2, name: 'black_widow', env: 'marvel' },
{ id: 3, name: 'wonder_woman', env: 'dc_comics' },
];
function hasCharacterFrom(env) {
return character => character.env === env;
}
console.log(characters.find(hasCharacterFrom('marvel')));
// { id: 1, name: 'ironman', env: 'marvel' }
console.log(characters.some(hasCharacterFrom('marvel')));
// true
讓我們面對它,Array.reduce不易理解。這是真的!但是,如果我們運行Array.filter然後再Array.map,感覺好像我們錯過了什麼,對吧?
我的意思是,我們瀏覽陣列兩次。第一次過濾並創建一個較短的陣列,第二次創建一個基於Array.filter的新陣列(再次!)。為了得到新陣列,用了兩種Array方法,每個方法都有自己的回調函數和一個我們之後都不會使用的陣列(由Array.filter創建的)。
避免這種低效,我建議使用Array.reduce。一樣的結果,更好的Code! Array.reduce允許我們過濾且把滿足條件的項目加到累加器(accumulator)中。例如,累加器可以是數字的累加、物件的填充、字串或陣列的連接。
在我們的例子中,我們一直使用Array.map,我建議使用帶有陣列的Array.reduce作為累加器進行連接。下面的例子,根據env的值決定是否將項目加入累加器。
'use strict';
const characters = [
{ name: 'ironman', env: 'marvel' },
{ name: 'black_widow', env: 'marvel' },
{ name: 'wonder_woman', env: 'dc_comics' },
];
console.log(
characters
.filter(character => character.env === 'marvel')
.map(character => Object.assign({}, character, { alsoSeenIn: ['Avengers'] }))
);
// [
// { name: 'ironman', env: 'marvel', alsoSeenIn: ['Avengers'] },
// { name: 'black_widow', env: 'marvel', alsoSeenIn: ['Avengers'] }
// ]
console.log(
characters
.reduce((acc, character) => {
return character.env === 'marvel'
? acc.concat(Object.assign({}, character, { alsoSeenIn: ['Avengers'] }))
: acc;
}, [])
)
// [
// { name: 'ironman', env: 'marvel', alsoSeenIn: ['Avengers'] },
// { name: 'black_widow', env: 'marvel', alsoSeenIn: ['Avengers'] }
// ]
希望有幫助。 如果您對本文有任何想法或有任何其他案例要顯示,請務必留下評論。 如果你發現它有用,請給原作一些鼓掌?並分享。 謝謝閱讀!
原文下方的評論: