譯者按: 做一個有追求的工程師,代碼不是隨便寫的! 原文: "Here’s how you can make better use of JavaScript arrays" 譯者: "Fundebug" 為了保證可讀性,本文采用意譯而非直譯。另外,本文版權歸原作者所有,翻譯僅用於學習。 小編推薦: ...
譯者按: 做一個有追求的工程師,代碼不是隨便寫的!
為了保證可讀性,本文采用意譯而非直譯。另外,本文版權歸原作者所有,翻譯僅用於學習。
小編推薦:Fundebug專註於JavaScript、微信小程式、微信小游戲,Node.js和Java線上bug實時監控。真的是一個很好用的bug監控服務,眾多大佬公司都在使用。
我保證這是一篇可以快速閱讀並吸收的文章。在過去的幾個月里,我檢查的所有的pull request中,都犯了這4個的錯誤。我寫這篇文章的另一個原因在於我自己也犯過這些錯。我們來看看如何正確地使用它們!
1. 不要使用Array.indexOf,使用Array.includes
“如果你要在數組中查找元素,使用Array.indexOf!”。記得在我學習JavaScript課程時候,有這樣一句話。這句話沒錯,確實可以這麼使用!
根據MDN文檔:“Array.indexOf會返回被查找元素第一個匹配的位置的下標。”因此,如果後面需要用到這個索引,Array.indexOf是一個很好的解法。
但是,我們要解決的問題是:查找數組中是否包含某個元素。這是一個Yes/No的問題,是一個返回布爾類型的真假問題。因此,我建議使用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
2. 不要使用Array.filter,使用Array.find
Array.filter是一個很有用的函數,它返回一個滿足過濾條件的新數組。正如其名字表達的含義,它是用來做過濾的。
但是,如果我們知道我們要的結果只有一個元素的時候,我就不建議使用它了。比如,如果我們的回調函數定義用一個唯一的ID來過濾,那麼結果必然唯一了。在這個情況下,Array.filter會返回只有一個元素的數組。因為既然能通過一個特定的ID來查找,我們已經確定只有一個元素了,那麼使用數組就沒有意義。
另外,我們再來聊聊性能問題。為了返回所有匹配的元素,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' }
3. 不要使用Array.find,使用Array.some
我承認我犯過很多次錯誤。後來,一個很要好的朋友讓我去看看MDN的文檔,說有更好的解決方案。這個情況和剛剛提到的Array.indexOf/Array.includes很像。
在前面的例子中,我們看到Array.find接受一個過濾函數,返回滿足的元素。那麼,如果我們要查找一個數組是否包含某個元素的時候,Array.find是否是最佳的方案呢?可能不是,因為它返回的是元素具體的值,而不是布爾值。
我推薦大家使用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
4. 不要使用Array.map和Array.filter組合,使用Array.reduce
Array.reduce有點難以理解!但是,如果我們每次在同時使用Array.filter和Array.map的時候,你是否覺察到需要點東西,對不?
我的意思是:我們對整個數組迴圈了2遍。第一次是過濾返回一個新的數組,第二次通過map又構造一個新的數組。我們使用了兩個數組方法,每一個方法都有各自的回調函數,而且Array.filter返回的數組以後再也不會用到。
為了避免低效率,我建議使用Array.reduce。同樣的結果,更優雅的代碼!請看下麵的例子:
'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'] }
// ]
備註
malgosiastp and David Piepgrass在評論中提到:在使用Array.find和Array.includes前請註意檢查相容性,因為最新的IE不支持。
關於Fundebug
Fundebug專註於JavaScript、微信小程式、微信小游戲、支付寶小程式、React Native、Node.js和Java實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了6億+錯誤事件,得到了Google、360、金山軟體等眾多知名用戶的認可。歡迎免費試用!
版權聲明:
轉載時請註明作者Fundebug以及本文地址:
https://blog.fundebug.com/2018/09/06/make-better-use-of-arrays/