JavaScript“新数组(n)”和“Array.prototype”。地图”古怪

时间:2022-12-29 21:17:41

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:

    >>> 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]

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

这是怎么回事?这是一个错误,还是我误解了如何使用新数组(3)?

12 个解决方案

#1


88  

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在运行这个函数的时候没有运行这个函数。

#2


61  

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 worked because: see Jonathan Lonowski's answer a few answers upper.

但这并没有起作用,因为:看到乔纳森·洛斯基的回答,有几个答案。

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

#3


42  

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

使用ES6,您可以做[…Array(10)]。map((a, b) => a),快速简单!

#4


13  

From the MDC page for map:

来自MDC页面的映射:

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

[…]回调仅用于指定值的数组的索引;[…]

[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.

[未定义]实际上是在索引上应用setter,这样映射就会迭代,而新数组(1)只是初始化索引(es),默认值为未定义,所以map跳过它。

I believe this is the same for all iteration methods.

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

#5


13  

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:

数组是不同的。不同之处在于,新数组(3)创建了一个长度为3但没有属性的数组,而[未定义的、未定义的、未定义的]则创建一个数组,其长度为3和3个属性,称为“0”、“1”和“2”,每个属性都具有未定义的值。你可以在操作符中看到区别:

"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中,它将返回未定义(而不是抛出错误,因为当你试图引用不存在的变量),这是你得到的一样,如果财产曾被显式设置为未定义。

#6


7  

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 technically empty array, there is nothing to be set.

所以实际发生的是,新数组()返回一个长度为3,但没有值的空数组。因此,当你运行x。在技术上是空的数组,没有什么可以设置的。

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

Firefox只是“填充”那些没有定义的空槽,尽管它没有任何值。

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的“更正确”,因为它表明数组中没有任何东西。

#7


5  

ES6 solution:

ES6解决方案:

[...Array(10)]

Doesn't work on typescript (2.3), though

不过,在typescript(2.3)上是不行的。

#8


4  

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}

数组(3)产生大致长度:3}

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

[未定义,未定义,未定义]创建编号属性:{0:未定义,1:未定义,2:未定义,长度:3}。

The map() implementation only acts on defined properties.

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

#9


3  

Not a bug. That's how the Array constructor is defined to work.

不是一个错误。这就是如何定义数组构造函数的方法。

From MDC:

争取*变革运动:

When you specify a single numeric parameter with the Array constructor, you specify the initial length of the array. The following code creates an array of five elements:

当您使用数组构造函数指定单个数字参数时,您将指定数组的初始长度。下面的代码创建了五个元素的数组:

var billingMethod = new Array(5);

The behavior of the Array constructor depends on whether the single parameter is a number.

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

The .map() method only includes in the iteration elements of the array that have explicitly had values assigned. Even an explicit assignment of undefined will cause a value to be considered eligible for inclusion in the iteration. That seems odd, but it's essentially the difference between an explicit undefined property on an object and a missing property:

map()方法只包含显式地赋值的数组的迭代元素。即使是未定义的显式赋值也会导致一个值被认为有资格在迭代中包含。这看起来很奇怪,但本质上是一个对象上的显式未定义属性和一个缺失的属性之间的区别:

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

The object x does not have a property called "z", and the object y does. However, in both cases it appears that the "value" of the property is undefined. In an array, the situation is similar: the value of length does implicitly perform a value assignment to all the elements from zero through length - 1. The .map() function therefore won't do anything (won't call the callback) when called on an array newly constructed with the Array constructor and a numeric argument.

对象x没有所谓的“z”属性,而对象是y。然而,在这两种情况下,属性的“值”似乎都没有定义。在数组中,情况类似:长度的值隐式地对所有元素执行值赋值,从零到长度- 1。因此,当调用一个新构造的数组构造函数和一个数字参数时,.map()函数不会做任何事情(不会调用回调)。

#10


3  

If you are doing this in order to easily fill up an array with values, can't use fill for 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.

如果您这样做是为了方便地填充一个带有值的数组,那么就不能使用填充来支持浏览器支持的原因,并且真的不想做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.

很丑,我不得不说,但至少问题和意图是很清楚地沟通的。

#11


3  

In ECMAScript 6th edition specification.

在ECMAScript第六版规范中。

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-len Step 9.

新数组(3)只定义属性长度,而不定义像{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-arrayaccumulation ElementList Step 5.

[未定义,未定义,未定义]将定义索引属性和长度属性,如{0:未定义,1:未定义,2:未定义,长度:3}。参见https://www.ecma-internationes.org/ecma -262/6.0/index.html# sec-runtimesemantics-arrayelementlist步骤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.

方法map,每个,一些,forEach, slice, reduce, reduceRight, filter of Array将通过HasProperty内部方法检查索引属性,所以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-internationes.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);

#12


-1  

In Chrome, if I do new Array(3) I get [], so my guess is that you've come across a browser bug.

在Chrome中,如果我做了新数组(3),那么我的猜测是你遇到了一个浏览器错误。

#1


88  

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在运行这个函数的时候没有运行这个函数。

#2


61  

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 worked because: see Jonathan Lonowski's answer a few answers upper.

但这并没有起作用,因为:看到乔纳森·洛斯基的回答,有几个答案。

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

#3


42  

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

使用ES6,您可以做[…Array(10)]。map((a, b) => a),快速简单!

#4


13  

From the MDC page for map:

来自MDC页面的映射:

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

[…]回调仅用于指定值的数组的索引;[…]

[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.

[未定义]实际上是在索引上应用setter,这样映射就会迭代,而新数组(1)只是初始化索引(es),默认值为未定义,所以map跳过它。

I believe this is the same for all iteration methods.

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

#5


13  

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:

数组是不同的。不同之处在于,新数组(3)创建了一个长度为3但没有属性的数组,而[未定义的、未定义的、未定义的]则创建一个数组,其长度为3和3个属性,称为“0”、“1”和“2”,每个属性都具有未定义的值。你可以在操作符中看到区别:

"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中,它将返回未定义(而不是抛出错误,因为当你试图引用不存在的变量),这是你得到的一样,如果财产曾被显式设置为未定义。

#6


7  

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 technically empty array, there is nothing to be set.

所以实际发生的是,新数组()返回一个长度为3,但没有值的空数组。因此,当你运行x。在技术上是空的数组,没有什么可以设置的。

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

Firefox只是“填充”那些没有定义的空槽,尽管它没有任何值。

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的“更正确”,因为它表明数组中没有任何东西。

#7


5  

ES6 solution:

ES6解决方案:

[...Array(10)]

Doesn't work on typescript (2.3), though

不过,在typescript(2.3)上是不行的。

#8


4  

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}

数组(3)产生大致长度:3}

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

[未定义,未定义,未定义]创建编号属性:{0:未定义,1:未定义,2:未定义,长度:3}。

The map() implementation only acts on defined properties.

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

#9


3  

Not a bug. That's how the Array constructor is defined to work.

不是一个错误。这就是如何定义数组构造函数的方法。

From MDC:

争取*变革运动:

When you specify a single numeric parameter with the Array constructor, you specify the initial length of the array. The following code creates an array of five elements:

当您使用数组构造函数指定单个数字参数时,您将指定数组的初始长度。下面的代码创建了五个元素的数组:

var billingMethod = new Array(5);

The behavior of the Array constructor depends on whether the single parameter is a number.

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

The .map() method only includes in the iteration elements of the array that have explicitly had values assigned. Even an explicit assignment of undefined will cause a value to be considered eligible for inclusion in the iteration. That seems odd, but it's essentially the difference between an explicit undefined property on an object and a missing property:

map()方法只包含显式地赋值的数组的迭代元素。即使是未定义的显式赋值也会导致一个值被认为有资格在迭代中包含。这看起来很奇怪,但本质上是一个对象上的显式未定义属性和一个缺失的属性之间的区别:

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

The object x does not have a property called "z", and the object y does. However, in both cases it appears that the "value" of the property is undefined. In an array, the situation is similar: the value of length does implicitly perform a value assignment to all the elements from zero through length - 1. The .map() function therefore won't do anything (won't call the callback) when called on an array newly constructed with the Array constructor and a numeric argument.

对象x没有所谓的“z”属性,而对象是y。然而,在这两种情况下,属性的“值”似乎都没有定义。在数组中,情况类似:长度的值隐式地对所有元素执行值赋值,从零到长度- 1。因此,当调用一个新构造的数组构造函数和一个数字参数时,.map()函数不会做任何事情(不会调用回调)。

#10


3  

If you are doing this in order to easily fill up an array with values, can't use fill for 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.

如果您这样做是为了方便地填充一个带有值的数组,那么就不能使用填充来支持浏览器支持的原因,并且真的不想做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.

很丑,我不得不说,但至少问题和意图是很清楚地沟通的。

#11


3  

In ECMAScript 6th edition specification.

在ECMAScript第六版规范中。

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-len Step 9.

新数组(3)只定义属性长度,而不定义像{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-arrayaccumulation ElementList Step 5.

[未定义,未定义,未定义]将定义索引属性和长度属性,如{0:未定义,1:未定义,2:未定义,长度:3}。参见https://www.ecma-internationes.org/ecma -262/6.0/index.html# sec-runtimesemantics-arrayelementlist步骤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.

方法map,每个,一些,forEach, slice, reduce, reduceRight, filter of Array将通过HasProperty内部方法检查索引属性,所以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-internationes.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);

#12


-1  

In Chrome, if I do new Array(3) I get [], so my guess is that you've come across a browser bug.

在Chrome中,如果我做了新数组(3),那么我的猜测是你遇到了一个浏览器错误。