一 问题描述

最近在开发中碰到一个很奇怪的问题,请看下面代码

const newArr = new Array(3).map((item) => {
  return item = {
    name: 'Chris xiong'
  }
})
console.log(newArr)

大家觉得这段代码的输出结果是多少呢?很多小伙伴会觉得结果一定是这样的
[{name: 'Chris xiong'}, {name: 'Chris xiong'}, {name: 'Chris xiong'}]
这么想的同学请把上面那段代码放进控制台里输出一下。你会发现,结果不是你想象的那样。上述这段代码的执行结果是(3) [undefined × 3]
大家一定会感到困惑,为什么输出的是undefined * 3呢?, 是因为我们的数组里的值是undefined,所以不能给undefined赋值嘛?先不着急,我们再来看下面一段代码

const arrA = [undefined, undefined, undefined]
const newArr = arrA.map((item) => {
  return item = {
     name: 'Chris xiong'
   }  
})
console.log(newArr)

如果上面的问题是因为数组的值是undefined造成的话,那么第二个demo也一定是(3) [undefined × 3]。那么事实又是什么呢?这里不卖关子了。这里的输出结果为
[{name: 'Chris xiong'}, {name: 'Chris xiong'}, {name: 'Chris xiong'}]
奇怪了,这里为什么又输出的是我们想要的结果呢?很气有没有?下面我们一起来探究一下这个让人困惑的问题。

二 原因探究

首先我们来看看Array.prototype.map的定义Array.prototype.map。大家注意这一句

callback is invoked only for indexes of the array which have assigned values, including undefined. It is not called for missing elements of the array (that is, indexes that have never been set, which have been deleted or which have never been assigned a value).

map函数的回调函数只会被数组中那些被赋予了值的项调用(包括赋了undefine的值),而不会被那些重来没有设置过值,或者被删除了的项调用。(注意这里的重来没有被赋给值)
那么现在我们就知道了,如果数组中的项没有被赋过值,那么这项就不能调用callback函数。
实际上new Array(x)这个操作不是创建一个x项都是undefined的数组,它创建的是一个只有长度的数组,里面的每项都是没有被赋过值的(可以想象new Array(3)实际上是创建了一个[, ,]的数组
我们来看下面一段代码

const arrA = [ , , ]
const newArr = arrA.map((item) => {
  return item = {
     name: 'Chris xiong'
   }  
})
console.log(newArr)

上面这段代码和第一段代码执行结果一样。
综合以上,我们找出了问题的原因。
(1)map函数的回调函数只会被赋过值的项调用。
(2)new Array(1) 和 [undefined]不一样。new Array(1)没有为数组中的项赋过值,而[undefined]为数组中的项赋了一个undefined值。

三 解决方法

那么如果我们想像上面那样创建一个新数组怎么办呢?知道原因就很简单了,我们在用new Array创建数组之后,再为数组的每一项随便赋个什么值就行了。一般使用fill方法

const newArr = new Array(3).fill().map((item) => {
  return item = {
    name: 'Chris xiong'
  }
})
console.log(newArr)

输出的结果就是
[{name: 'Chris xiong'}, {name: 'Chris xiong'}, {name: 'Chris xiong'}]

注:
(1) fill函数为数组填充值。fill函数


淼淼真人
1.1k 声望202 粉丝

一个前端菜鸟!