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
JavaScript "new Array(n)" and "Array.prototype.map" weirdness
提问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 in
operator:
数组不一样。区别在于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
:
[...]
callback
is invoked only for indexes of the array which have assigned value; [...]
[...]
callback
仅对已分配值的数组索引调用;[...]
[undefined]
actually applies the setter on the index(es) so that map
will iterate, whereas new Array(1)
just initializes the index(es) with a default value of undefined
so map
skips 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 length
and 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-arrayaccumulationElementList
Step 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
, filter
of Array will check the index property by HasProperty
internal 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.map
on a technicallyempty array, there is nothing to be set.
所以实际发生的是 new Array() 返回一个空数组,它的长度为 3,但没有值。因此,当您x.map
在技术上为空的数组上运行时,无需设置任何内容。
Firefox just 'fills in' those empty slots with undefined
even 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.
我不得不说相当丑陋,但至少问题和意图传达得很清楚。