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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5501581/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:29:32  来源:igfitidea点击:

JavaScript "new Array(n)" and "Array.prototype.map" weirdness

javascriptarraysmap-function

提问by rampion

I've observed this in Firefox-3.5.7/Firebug-1.5.3 and Firefox-3.6.16/Firebug-1.6.2

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

When I fire up Firebug:

当我启动 Firebug 时:

var x = new Array(3)
console.log(x) 
// [undefined, undefined, undefined]

var y = [undefined, undefined, undefined]
console.log(y) 
// [undefined, undefined, undefined]

console.log( x.constructor == y.constructor) // true

console.log( 
  x.map(function() { return 0; })
)
// [undefined, undefined, undefined]

console.log(
  y.map(function() { return 0; })
)
// [0, 0, 0]

What's going on here? Is this a bug, or am I misunderstanding how to use new Array(3)?

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

采纳答案by David M?rtensson

It appears that the first example

看来第一个例子

x = new Array(3);

Creates an array with undefined pointers.

创建一个带有未定义指针的数组。

And the second creates an array with pointers to 3 undefined objects, in this case the pointers them self are NOT undefined, only the objects they point to.

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

y = [undefined, undefined, undefined]
// The following is not equivalent to the above, it's the same as new Array(3)
y = [,,,];

As map is run in the context of the objects in the array I believe the first map fails to run the function at all while the second manages to run.

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

回答by cstuncsik

I had a task that I only knew the length of the array and needed to transform the items. I wanted to do something like this:

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

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

To quickly create an array like this:

要快速创建这样的数组:

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

But it didn't work because: (see Jonathan Lonowski's answer a few answers above)

但它没有用,因为:(请参阅 Jonathan Lonowski 的回答上面的几个答案)

The solution could be to fill up the array items with any value (even with undefined) using Array.prototype.fill()

解决方案可能是使用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));

Update

更新

Another solution could be:

另一种解决方案可能是:

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

console.log(Array.apply(null, Array(10)).map((val, idx) => idx));

回答by Manuel Beaudru

With ES6, you can do [...Array(10)].map((a, b) => a), quick and easy!

使用 ES6,您可以[...Array(10)].map((a, b) => a)轻松快捷地完成!

回答by Serge Intern

ES6 solution:

ES6解决方案:

[...Array(10)]

Doesn't work on typescript (2.3), though

但不适用于打字稿(2.3)

回答by Tim Down

The arrays are different. The difference is that new Array(3)creates an array with a length of three but no properties, while [undefined, undefined, undefined]creates an array with a length of three and three properties called "0", "1" and "2", each with a value of undefined. You can see the difference using the inoperator:

数组不一样。区别在于new Array(3)创建一个长度为三个但没有属性[undefined, undefined, undefined]的数组,而创建一个长度为三个的数组和三个名为“0”、“1”和“2”的属性,每个属性的值为undefined。您可以使用in运算符查看差异:

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

This stems from the slightly confusing fact that if you try to get the value of a non-existent property of any native object in JavaScript, it returns undefined(rather than throwing an error, as happens when you try to refer to a non-existent variable), which is the same as what you get if the property has previously been explictly set to undefined.

这源于一个稍微令人困惑的事实,即如果您尝试获取 JavaScript 中任何本机对象的不存在属性的值,它将返回undefined(而不是抛出错误,就像您尝试引用不存在的变量时发生的那样) ),这与如果该属性之前已显式设置为undefined.

回答by Jonathan Lonowski

From the MDC page for map:

从 MDC 页面获取map

[...] callbackis invoked only for indexes of the array which have assigned value; [...]

[...]callback仅对已分配值的数组索引调用;[...]

[undefined]actually applies the setter on the index(es) so that mapwill iterate, whereas new Array(1)just initializes the index(es) with a default value of undefinedso mapskips it.

[undefined]实际上在索引上应用 setter 以便map迭代,而new Array(1)只是使用默认值初始化索引undefined所以map跳过它。

I believe this is the same for all iteration methods.

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

回答by wenshin

In ECMAScript 6th edition specification.

在 ECMAScript 第 6 版规范中。

new Array(3)only define property lengthand do not define index properties like {length: 3}. see https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array-lenStep 9.

new Array(3)只定义属性length,不定义索引属性,如{length: 3}. 参见https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array-len第 9 步。

[undefined, undefined, undefined]will define index properties and length property like {0: undefined, 1: undefined, 2: undefined, length: 3}. see https://www.ecma-international.org/ecma-262/6.0/index.html#sec-runtime-semantics-arrayaccumulationElementListStep 5.

[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-arrayaccumulationElementList第 5 步。

methods map, every, some, forEach, slice, reduce, reduceRight, filterof Array will check the index property by HasPropertyinternal method, so new Array(3).map(v => 1)will not invoke the callback.

Array 的methods map, every, some, forEach, slice, reduce, reduceRight,filter将通过HasProperty内部方法检查 index 属性,因此new Array(3).map(v => 1)不会调用回调。

for more detail, see https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array.prototype.map

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

How to fix?

怎么修?

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);

回答by helloandre

I think the best way to explain this is to look at the way that Chrome handles it.

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

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

So what is actually happening is that new Array() is returning an empty array that has a length of 3, but no values. Therefore, when you run x.mapon a technicallyempty array, there is nothing to be set.

所以实际发生的是 new Array() 返回一个空数组,它的长度为 3,但没有值。因此,当您x.map技术上为空的数组上运行时,无需设置任何内容。

Firefox just 'fills in' those empty slots with undefinedeven though it has no values.

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

I don't think this is explicitly a bug, just a poor way of representing what is going on. I suppose Chrome's is "more correct" because it shows that there isn't actually anything in the array.

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

回答by Vezquex

Just ran into this. It sure would be convenient to be able to use Array(n).map.

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

Array(3)yields roughly {length: 3}

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

[undefined, undefined, undefined]creates the numbered properties:
{0: undefined, 1: undefined, 2: undefined, length: 3}.

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

The map() implementation only acts on defined properties.

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

回答by Alex

If you are doing this in order to easily fill up an array with values, can't use fillfor browser support reasons and really don't want to do a for-loop, you can also do x = new Array(3).join(".").split(".").map(...which will give you an array of empty strings.

如果您这样做是为了轻松地用值填充数组,出于浏览器支持的原因不能使用fill并且真的不想做 for 循环,您也可以这样做x = new Array(3).join(".").split(".").map(...,这会给您一个空数组字符串。

Quite ugly I have to say, but at least the problem and intention are quite clearly communicated.

我不得不说相当丑陋,但至少问题和意图传达得很清楚。