1. 程式人生 > >JavaScript中Array的正確使用方式

JavaScript中Array的正確使用方式

在 JavaScript 中正確使用地使用 Array 的方法如下:

用 Array.includes 代替 Array.indexOf

“如果你要在陣列中查詢元素,請使用 Array.indexOf”。

MDN 文件寫道,Array.indexOf 將“返回第一次出現給定元素的索引”。因此,如果我們稍後要在程式碼中使用這個返回的索引,那麼使用 Array.indexOf 找到索引就對了。

但是,如果我們只想知道陣列是否包含某個值,該怎麼辦?這似乎是一個是與否的問題,或者說是一個布林值問題。對於這種情況,建議使用返回布林值的 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.find 而不是 Array.filter

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' } 

用 Array.some 代替 Array.find

我承認這個錯誤我犯了很多次。然後,一位善良的朋友告訴我,最好可以先參考 MDN 文件。這與上面的 Array.indexOf/Array.includes 非常相似。

在前面的例子中,我們看到 Array.find 需要一個回撥函式作為引數,並返回一個元素。如果我們想要知道陣列是否包含某個值,Array.find 是最好的解決方案嗎?可能不是,因為它返回的是一個元素值,而不是一個布林值。

對於這種情況,建議使用 Array.some,它返回所需的布林值。另外,從語義上看,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.reduce 不容易理解。事實確實如此!但是,如果我們使用 Array.filter 和 Array.map 的組合,總感覺缺少了什麼,我們遍歷了兩次陣列。第一次過濾陣列並建立一個較短的陣列,第二次又基於 Array.filter 獲得陣列建立一個包含新值的陣列。為了獲得我們想要的新陣列,我們使用了兩個 Array 方法。每個方法都有自己的回撥函式和一個用不到的陣列——由 Array.filter 建立的那個陣列。

為了避免這種效能損耗,建議是使用 Array.reduce。結果是一樣的,程式碼卻更簡單! 我們可以使用 Array.reduce 進行過濾,並將目標元素新增到累加器中。累加器可以是遞增的數字、要填充的物件、要連線的字串或陣列。

在我們的例子中,因為之前使用了 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'] }  // ]