Javascript 对使用“new”创建的数组上的“map”行为感到困惑`

Javascript 对使用“new”创建的数组上的“map”行为感到困惑`,javascript,arrays,map,new-operator,Javascript,Arrays,Map,New Operator,我被mapping使用new创建的数组的结果弄糊涂了: function returnsFourteen() { return 14; } var a = new Array(4); > [undefined x 4] in Chrome, [, , , ,] in Firefox a.map(returnsFourteen); > [undefined x 4] in Chrome, [, , , ,] in Firefox var b = [undefined, un

我被
map
ping使用
new
创建的数组的结果弄糊涂了:

function returnsFourteen() {
    return 14;
}

var a = new Array(4);
> [undefined x 4] in Chrome, [, , , ,] in Firefox
a.map(returnsFourteen);
> [undefined x 4] in Chrome, [, , , ,] in Firefox

var b = [undefined, undefined, undefined, undefined];
> [undefined, undefined, undefined, undefined]
b.map(returnsFourteen);
> [14, 14, 14, 14]
我希望
a.map(returnsFourteen)
返回
[14,14,14,14]
(与
b.map(returnsFourteen)
,因为根据

如果传递给数组构造函数的唯一参数是整数 在0和2**32-1(含)之间,将创建一个新的JavaScript数组 有那么多的元素

var b = [undefined, undefined, undefined, undefined];
我认为这意味着
a
应该有4个元素

我错过了什么

var a = new Array(4);
这将定义一个显式长度为4但没有元素的新数组对象

var b = [undefined, undefined, undefined, undefined];
这将定义一个隐式长度为4的新数组对象,其中包含4个元素,每个元素的值
未定义

从:

仅对已分配的数组的索引调用回调 值;对于已删除的索引或 从未分配过值

对于数组
a
,没有已赋值的元素,因此它不执行任何操作


对于数组
b
,有四个元素被赋值(是的,
未定义的
是一个值),因此当您创建这样的数组时,它会将所有四个元素映射到编号
14

var arr1 = new Array( 4 );
您得到的数组长度为
4
,但没有元素。这就是为什么
map
不转换数组-数组没有要转换的元素

另一方面,如果您这样做:

var arr2 = [ undefined, undefined, undefined, undefined ];
您得到的和数组的长度也为
4
,但它有4个元素

var b = [undefined, undefined, undefined, undefined];
请注意没有元素和具有值为
未定义
的元素之间的区别。不幸的是,在这两种情况下,属性访问器表达式的计算结果都是
未定义
值,因此:

arr1[0] // undefined
arr2[0] // undefined
但是,有一种方法可以区分这两种阵列:

'0' in arr1 // false
'0' in arr2 // true
newarray(len)
创建一个空数组,并执行与用
未定义的值填充数组不同的操作:它将其长度设置为
len
。因此,它转换为以下代码:

var newArr = [];
newArr.length = len;
让我们来享受一下
newArr
(假设
len=4
):

这是因为虽然有4个项目长,但它不包含这4个项目中的任何一个。想象一下一个空的子弹夹:它有空间容纳(比如)20个子弹,但它不包含任何子弹。它们甚至没有设置为值
undefined
,它们只是…undefined(这有点让人困惑)

现在,
Array.prototype.map
愉快地沿着你的第一个数组走着,唧唧喳喳,吹着口哨,每次它看到一个数组项,它都会调用一个函数。但是,当它沿着空的子弹夹走着时,它看不到子弹。当然,子弹是有空间的,但这并不意味着它们的存在。在这里,没有价值,因为映射到该值的ch不存在

对于第二个数组,它填充了
未定义的
值,值是
未定义的
,键也是如此。在
b[1]
b[3]
中有一些内容,但这些内容没有定义;但是
array.prototype.map
并不重要,只要有键,它将对任何值进行操作

对于规范中的进一步检查:

  • 新阵列(len)
  • Array.prototype.map
    :(请密切注意步骤8.b)

关于
console.log
行为的另一个答案。非常简单,输出是sugar,技术上是错误的

让我们考虑这个例子:

var foo = new Array(4),
    bar = [undefined, undefined, undefined, undefined];

console.log( Object.getOwnPropertyNames(bar) );
console.log( Object.getOwnPropertyNames(foo) );
正如我们在结果中看到的那样,
.getOwnPropertyNames
函数返回

["length"]
对于
foo
数组/对象,但是

["length", "0", "1", "2", "3"]
用于
数组/对象


因此,
console.log
只是在输出
array
时愚弄了你,这些数组只有一个定义的
.length
,但没有实际的属性分配。

.map()
的工作方式不是破坏性的,试着将结果分配回
a
奇怪的是,如果你这样做
console.log(a,b)在任何映射之前,它返回:
[undefined×4][undefined,undefined,undefined,undefined]
(在Chrome中)@尼尔:那只是
控制台
糖。实际上,我们有一个
数组
,长度为4@jAndy呃,他们应该记录同样的事情,不是吗?@Matt:那么,在我看来,这不是一个好问题。你在文档中指出了一个有争议的段落,这很好,但也可以解决,然后问题就不存在了不再存在。这更适合作为某种bug报告或其他地方的讨论(例如:)。那么MDN文档中的引用--
一个新的JavaScript数组是用那个数量的元素创建的,是错误的,还是我误解了它?对我来说,这似乎意味着实际上有带值的元素。@MattFenwick文档是正确的。
未定义的元素和元素之间有一个重要的区别如果MDN的值
未定义
@jbabey,但是
新数组(4)
会创建一个没有元素的数组,因此MDN文档是不正确的……根据MDN,该数组将有4个元素。@jbabey我不同意。数组元素是一个属性,属性名称是数组索引(非负整数,或表示此类数字的字符串:
'1'
'2'
'3'
等)。未指定将任何元素添加到新创建的数组中。此外,当使用此类数组调用
对象.getOwnPropertyNames
时,结果将包含
'length'
字符串,但不包含数组索引。因此,数组不包含任何元素,而仅包含
'length'
属性。以查看@jAndy的答案了解详细信息。此外,大多数
conso