中电科旗下高技能it教育培训机构

在javascript中更好地使用数组 -注册电子游戏平台

400-9988-316

在javascript中更好地使用数组

发布时间:2021-01-29浏览量:714次

使用 array.includes 替代 array.indexof

如果需要在数组中查找某个元素,请使用 array.indexof。在 mdn 文档中,对 array.indexof 的描述是:返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。因此,如果在之后的代码中需要用到(给给定元素的)索引,那么 array.indexof 是不二之选。

然而,如果我们仅需要知道数组中是否包含给定元素呢?这意味着只是是与否的区别,这是一个布尔问题(boolean question)。针对这种情况,我建议使用直接返回布尔值的 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 是一个十分有用的方法。它通过回调函数过滤原数组,并将过滤后的项作为新数组返回。正如它的名字所示,我们将这个方法用于过滤,(一般而言)会获得一个长度更短的新数组。

然而,如果知道经回调函数过滤后,只会剩余唯一的一项,那么我不建议使用 array.filter。比如:使用等于某个唯一 id 为过滤条件去过滤一个数组。在这个例子中,array.filter 返回一个仅有一项的新数组。然而,我们仅仅是为了获取 id 为特定 id 的那一项,这个新数组显得毫无用处。

让我们讨论一下性能。为了获取所有符合回调函数过滤条件的项,array.filter 必须遍历整个数组。如果原数组中有成千上万项,回调函数需要执行的次数是相当多的。

为避免这些情况,我建议使用 array.find。它与 array.filter 一样需要一个回调函数,(但只是返回)符合条件的第一项。当找到符合回调函数过滤条件的第一个元素时,它会立即停止往下的搜寻。不再遍历整个数组。


'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

在上面的例子中,我们知道 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


补充一下 array.some 与 array.includes 使用上的区别。两者都返回一个布尔值,表示某项是否存在于数组之中,一旦找到对应的项,立即停止遍历数组。不同的是 array.some 的参数是回调函数,而 array.includes 的参数是一个值(均不考虑第二个可选参数)。

假设希望知道值为 value 的项是否存在于数组中,既可以编写代码:[].includes(value), 也可以给 array.some 传入 item => item === value 作为回调函数。array.includes 使用更简单,array.some 可操控性更强。

使用 array.reduce 替代 array.filter 与 array.map 的组合

事实上说,array.reduce 不太容易理解。然而,如果我们先使用 array.filter 过滤原数组,之后(对结果)再调用 array.map (以获取一个新数组)。这看起似乎有点问题,是我们忽略了什么吗?

这样做的问题是:我们遍历了两次数组。第一次是过滤原数组以获取一个长度稍短的新数组,第二次遍历(译者注:指 array.map)是对array.filter 的返回的新数组进行加工,再次创造了一个新数组!为得到最终的结果,我们结合使用了两个数组方法。每个方法都有它自己的回调函数,而且供 array.map 使用的临时数组是由 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'] }

// ]