JavaScript数组map方法的疑问[已解决]

问题
一个长度为4空数组
map()给数组元素赋值
为什么新数组还是空的呢?

下面的代码为什么不输出
[empty × 4]    [2,2,2,2]

代码

var array = new Array(4);
var newArray = array.map(item=>{
    return '2'
});
console.log(array,newArray);
// =>[empty × 4]   [empty × 4]

解决

普通方法无法遍历稀疏数组,只能用1楼所说的特殊方法才能遍历
阅读 10.6k
5 个回答

什么都没有的数组元素叫做槽(slot),一般方法都会忽略,可以用 Array.prototype.fillArray.from 或者 [...arr] 的方式转换。

比如 Array.from(new Array(4))

这个你需要通过阅读V8引擎的源代码来获取答案:

function ArrayMap(f, receiver) {
  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map");

  // Pull out the length so that modifications to the length in the
  // loop will not affect the looping and side effects are visible.
  var array = TO_OBJECT(this);
  var length = TO_LENGTH(array.length);
  if (!IS_CALLABLE(f)) throw %make_type_error(kCalledNonCallable, f);
  var result = ArraySpeciesCreate(array, length);
  for (var i = 0; i < length; i++) {
    if (i in array) {
      var element = array[i];
      %CreateDataProperty(result, i, %_Call(f, receiver, element, i, array));
    }
  }
  return result;
}

在这里,我们注意到,它首先是用了一个TO_OBJECT来把数组转为了对象,然后用了一个for循环在对象中查找下标,也就是这一句话:if (i in array),而当我们用new Array(4)来创建数组时,实际创建的只是一个指针,并没有创建实体的4个元素,所以当它被转化为对象时,得到是{}这样的空对象,所以这里的每一个if语句分枝都不会被执行。

但如果我们用var array = [null, null, null, null]或者哪怕array = [undefined, undefined, undefined, undefined]来做,效果都会大不一样,因为以这样方式创建的数组,转化为的对象是:

{
  0: undefined,
  1: undefined,
  2: undefined,
  3: undefined,
}

当对这样的对象进行if (i in array)操作时,可以找到相应的下标,所以可以依次执行。这就是根本原因。

Array.map的callback只会针对已经赋值过的item进行调用(包括undefined)。
所以当有的元素被删除了,或者从来没有被赋值的时候,callback不会调用这个元素。

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函数逻辑有关系,使用你的代码我发现map函数并有遍历四次,其实一次都没遍历。具体的问题需要看看map内部实现才晓得了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏