JavaScript“new Array(n)”和“Array.prototype.map”怪异

我已经在Firefox-3.5.7 / Firebug-1.5.3和Firefox-3.6.16 / Firebug-1.6.2中观察到了这一点

当我激发Firebug时:

>>> x = new Array(3) [undefined, undefined, undefined] >>> y = [undefined, undefined, undefined] [undefined, undefined, undefined] >>> x.constructor == y.constructor true >>> x.map(function(){ return 0; }) [undefined, undefined, undefined] >>> y.map(function(){ return 0; }) [0, 0, 0] 

这里发生了什么? 这是一个错误,或者我误解如何使用new Array(3)

看来,第一个例子

 x = new Array(3); 

用undefined指针创build一个数组。

第二个创build一个指向3个未定义对象的数组,在这种情况下,它们自己的指针不是未定义的,只是它们指向的对象。

 y = [undefined, undefined, undefined] 

由于映射在数组中的对象的上下文中运行,我相信第一个映射无法运行该函数,而第二个映射却无法运行。

我有一个任务,我只知道数组的长度,需要转换的项目。 我想要做这样的事情:

 let arr = new Array(10).map((val,idx) => idx); 

要快速创build一个这样的数组:

 [0,1,2,3,4,5,6,7,8,9] 

但它没有奏效,因为:请参阅Jonathan Lonowski的答案上面的几个答案。

解决scheme可以是使用Array.prototype.fill()填充任何值的数组项(即使未定义)

 let arr = new Array(10).fill(undefined).map((val,idx) => idx); 
 console.log(new Array(10).fill(undefined).map((val, idx) => idx)); 

有了ES6,你可以做[...Array(10)].map((a, b) => a) ,快速简单!

arrays是不同的。 不同的是, new Array(3)创build一个长度为三,但没有属性的数组,而[undefined, undefined, undefined]创build一个数组长度为三个和三个属性称为“0”,“1”和“ 2“,每个值都是undefined 。 你可以使用in运算符看到不同之in

 "0" in new Array(3); // false "0" in [undefined, undefined, undefined]; // true 

这起源于一个稍微混淆的事实,即如果您试图在JavaScript中获取任何本机对象的不存在的属性的值,它将返回undefined (而不是抛出一个错误,就像您尝试引用一个不存在的variables),如果该属性以前被undefined地设置为undefined ,那么这与你所得到的一样。

从MDC页面查看map

[…] callback仅针对已赋值的数组的索引; […]

[undefined]实际上将setter应用于索引(es),以便map将迭代,而new Array(1)仅使用undefined的默认值初始化索引(es),以便map跳过它。

我相信这对所有迭代方法都是一样的。

我认为解释这个最好的方法是看看Chrome处理它的方式。

 >>> x = new Array(3) [] >>> x.length 3 

那么实际发生的是新的Array()返回一个长度为3,但没有值的空数组。 因此,当您在技术上空的数组上运行x.map时,没有任何设置。

即使没有任何值,Firefox也只是“填充”那些undefined空槽。

我不认为这是一个明确的错误,只是表示正在发生的一种糟糕的方式。 我想Chrome是“更正确的”,因为它表明实际上没有任何数组。

刚刚碰到这个。 能够使用Array(n).map确实会很方便。

Array(3)大致产生{length: 3}

[undefined, undefined, undefined]创build编号的属性:
{0: undefined, 1: undefined, 2: undefined, length: 3}

map()实现仅对定义的属性起作用。

不是一个错误。 这就是数组构造函数定义的工作方式。

从MDC:

当您使用Array构造函数指定单个数字参数时,可以指定数组的初始长度。 以下代码创build了一个由五个元素组成的数组:

 var billingMethod = new Array(5); 

数组构造函数的行为取决于单个参数是否是数字。

.map()方法只在数组的迭代元素中包含明确赋值的元素。 即使是明确的undefined分配也会导致一个值被认为有资格包含在迭代中。 这似乎很奇怪,但它本质上是一个对象上的明确的undefined属性和缺less的属性之间的区别:

 var x = { }, y = { z: undefined }; if (xz === yz) // true 

对象x不具有称为“z”的属性,而对象y具有。 然而,在这两种情况下,财产的“价值”似乎是undefined 。 在一个数组中,情况是相似的: length值确实隐含地执行从零到length - 1所有元素的赋值。 因此.map()函数在用Array构造函数和数字参数新构造的数组上调用时不会执行任何操作(不会调用callback函数)。

如果你这样做是为了方便地用数组填充一个数组,不能使用fill来满足浏览器支持的原因,也不希望做一个for循环,你也可以使用x = new Array(3).join(".").split(".").map(...这会给你一个空string的数组。

相当丑陋的我不得不说,但至less问题和意图是相当清楚的沟通。

在ECMAScript第六版规范中。

new Array(3)只能定义属性的length ,不能像{length: 3}那样定义索引属性。 请参阅https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array-len第9步。;

[undefined, undefined, undefined]会定义像{0: undefined, 1: undefined, 2: undefined, length: 3}这样的索引属性和长度属性。 请参阅https://www.ecma-international.org/ecma-262/6.0/index.html#sec-runtime-semantics-arrayaccumulation ElementList步骤5。

方法mapreduceRightsomeforEachslicereducereduceRight ,Array的filter将通过HasProperty内部方法检查索引属性,所以new Array(3).map(v => 1)不会调用callback。

有关更多详细信息,请参阅https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array.prototype.map

怎么修?

 let a = new Array(3); a.join('.').split('.').map(v => 1); let a = new Array(3); a.fill(1); let a = new Array(3); a.fill(undefined).map(v => 1); let a = new Array(3); [...a].map(v => 1); 

ES6解决scheme:

 [...Array(10)] 

不过,在打字稿(2.3)上不起作用

在Chrome中,如果我做new Array(3)我得到[] ,所以我的猜测是你遇到了一个浏览器错误。