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