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。
方法map
, reduceRight
, some
, forEach
, slice
, reduce
, reduceRight
,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)
我得到[]
,所以我的猜测是你遇到了一个浏览器错误。