为什么“map”方法显然不适用于通过“new Array(count)”创建的数组?
我在 Firefox-3.5.7/Firebug-1.5.3 和 Firefox-3.6.16/Firebug-1.6.2 中观察到这一点
当我启动 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]
这是怎么回事?这是一个错误,还是我误解了如何使用new Array(3)
?
I've observed this in Firefox-3.5.7/Firebug-1.5.3 and Firefox-3.6.16/Firebug-1.6.2
When I fire up 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)
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
这是一个简单的实用方法作为解决方法:
Simple mapFor
完整示例
这是一个更完整的示例(带有健全性检查),它还允许指定可选的起始索引:
倒计时
操作传递给回调的索引可以倒数:
Here's a simple utility method as a workaround:
Simple mapFor
Complete Example
Here's a more complete example (with sanity checks) which also allows specifying an optional starting index:
Counting Down
Manipulating the index passed to the callback allows counting backwards:
看来第一个示例
创建了一个长度为 3 但没有任何元素的数组,因此未创建索引 [0]、[1] 和 [2]。
第二个创建一个包含 3 个未定义对象的数组,在这种情况下,它们自己创建了索引/属性,但它们引用的对象未定义。
由于映射在索引/属性列表上运行,而不是在设置的长度上运行,因此如果没有创建索引/属性,它将不会运行。
It appears that the first example
Creates an array with a length of 3 but without any elements, so the indices [0], [1] and [2] is not created.
And the second creates an array with the 3 undefined objects, in this case the indices/properties them self are created but the objects they refer to are undefined.
As map runs on the list of indices/properties, not on the set length, so if no indices/properties is created, it will not run.
使用 ES6,您可以快速轻松地执行
[...Array(10)].map((a, b) => a)
!With ES6, you can do
[...Array(10)].map((a, b) => a)
, quick and easy!ES6 解决方案:
但不适用于 typescript (2.3)
ES6 solution:
Doesn't work on typescript (2.3), though
来自
map
:[undefined]
实际上将 setter 应用于索引,以便map
进行迭代,而new Array(1)
只是使用默认值undefined
初始化索引,因此map
会跳过它。我相信这对于所有迭代方法都是相同的。
From the MDC page for
map
:[undefined]
actually applies the setter on the index(es) so thatmap
will iterate, whereasnew Array(1)
just initializes the index(es) with a default value ofundefined
somap
skips it.I believe this is the same for all iteration methods.
由于其他答案中彻底解释的原因, Array(n).map 不起作用。但是,在 ES2015 中
Array.from
接受一个地图函数:For reasons thoroughly explained in other answers,
Array(n).map
doesn't work. However, in ES2015Array.from
accepts a map function:数组不同。区别在于
new Array(3)
创建一个长度为 3 但没有属性的数组,而[undefined, undefined, undefined]
创建一个长度为 3 的数组三个和三个属性分别称为“0”、“1”和“2”,每个属性的值为未定义
。您可以使用in
运算符看到差异:这源于一个有点令人困惑的事实,即如果您尝试获取 JavaScript 中任何本机对象的不存在属性的值,它会返回
undefined(而不是抛出错误,就像您尝试引用不存在的变量时发生的那样),这与之前已将属性显式设置为 undefined 时得到的结果相同代码>.
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 ofundefined
. You can see the difference using thein
operator: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 toundefined
.在 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:未定义,1:未定义,2:未定义,长度:3}
。请参阅 https://www.ecma- International.org/ecma-262/6.0/index.html#sec-runtime-semantics-arrayaccumulationElementList
步骤 5.方法
map
、every
、一些
、forEach
、切片
、reduce
、reduceRight
、 Array 的filter
会通过HasProperty
内部方法检查索引属性,因此new Array(3).map(v => 1)
将不调用回调。有关更多详细信息,请参阅 https:// www.ecma-international.org/ecma-262/6.0/index.html#sec-array.prototype.map
如何修复?
In ECMAScript 6th edition specification.
new Array(3)
only define propertylength
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.[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.methods
map
,every
,some
,forEach
,slice
,reduce
,reduceRight
,filter
of Array will check the index property byHasProperty
internal method, sonew Array(3).map(v => 1)
will not invoke the callback.for more detail, see https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array.prototype.map
How to fix?
我认为解释这一点的最好方法是看看 Chrome 处理它的方式。
所以实际发生的情况是 new Array() 返回一个长度为 3 的空数组,但没有值。因此,当您在技术上空数组上运行
x.map
时,无需设置任何内容。Firefox 只是用
undefined
'填充'那些空槽,即使它没有值。我不认为这明显是一个错误,只是一种糟糕的表示正在发生的事情的方式。我认为 Chrome 的“更正确”,因为它表明数组中实际上没有任何内容。
I think the best way to explain this is to look at the way that Chrome handles it.
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.Firefox just 'fills in' those empty slots with
undefined
even though it has no values.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.
不是错误。这就是数组构造函数的定义方式。
来自MDC:
.map()
方法仅包含已显式分配值的数组的迭代元素。即使显式分配undefined
也会导致某个值被视为有资格包含在迭代中。这看起来很奇怪,但这本质上是对象上的显式undefined
属性和缺失属性之间的区别:对象
x
没有名为“z”的属性,并且对象y
会这样做。然而,在这两种情况下,属性的“值”似乎都是未定义
。在数组中,情况类似:length
的值确实隐式地对从 0 到length - 1
的所有元素执行赋值。因此,当在使用 Array 构造函数和数字参数新构造的数组上调用时,.map()
函数不会执行任何操作(不会调用回调)。Not a bug. That's how the Array constructor is defined to work.
From MDC:
The
.map()
method only includes in the iteration elements of the array that have explicitly had values assigned. Even an explicit assignment ofundefined
will cause a value to be considered eligible for inclusion in the iteration. That seems odd, but it's essentially the difference between an explicitundefined
property on an object and a missing property:The object
x
does not have a property called "z", and the objecty
does. However, in both cases it appears that the "value" of the property isundefined
. In an array, the situation is similar: the value oflength
does implicitly perform a value assignment to all the elements from zero throughlength - 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.刚刚遇到这个。能够使用 Array(n).map 肯定会很方便。
Array(3)
大致产生{length: 3}
[undefined, undefined, undefined]
创建编号属性:{0:未定义,1:未定义,2:未定义,长度:3}
。map() 实现仅作用于定义的属性。
Just ran into this. It sure would be convenient to be able to use
Array(n).map
.Array(3)
yields roughly{length: 3}
[undefined, undefined, undefined]
creates the numbered properties:{0: undefined, 1: undefined, 2: undefined, length: 3}
.The map() implementation only acts on defined properties.
如果您这样做是为了轻松地用值填充数组,则不能使用 fill 出于浏览器支持原因并且确实不想执行 for 循环,您也可以执行
x = new Array(3).join(".") .split(".").map(...
将为您提供一个空字符串数组。我不得不说,这很丑陋,但至少问题和意图传达得相当清楚。
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.Quite ugly I have to say, but at least the problem and intention are quite clearly communicated.
既然问题是为什么,这就和 JS 的设计方式有关。
我可以想到两个主要原因来解释这种行为:
性能:给定
x = 10000
和new Array(x)
构造函数明智的做法是避免从 0 到 10000 循环以使用未定义
值填充数组。隐式“未定义”:给出
a = [undefined, undefined]
和b = new Array(2)
、a[1]
和b[1]
都会返回undefined
,但a[8]
和b[8]
也会返回即使它们超出范围,也返回undefined
。最终,符号
empty x 3
是避免设置和显示一长串未定义
值的快捷方式,这些值无论如何都是未定义
因为它们不是明确声明。注意:给定数组
a = [0]
和a[9] = 9
,console.log(a)
将返回( 10) [0,empty x 8, 9]
,通过返回显式声明的两个值之间的差异来自动填充间隙。Since the question is why, this has to do with how JS was designed.
There are 2 main reasons I can think of to explain this behavior:
Performance: Given
x = 10000
andnew Array(x)
it is wise for the constructor to avoid looping from 0 to 10000 to fill the array withundefined
values.Implicitly "undefined": Give
a = [undefined, undefined]
andb = new Array(2)
,a[1]
andb[1]
will both returnundefined
, buta[8]
andb[8]
will also returnundefined
even if they're out of range.Ultimately, the notation
empty x 3
is a shortcut to avoid setting and displaying a long list ofundefined
values that areundefined
anyway because they are not declared explicitly.Note: Given array
a = [0]
anda[9] = 9
,console.log(a)
will return(10) [0, empty x 8, 9]
, filling the gap automatically by returning the difference between the two values declared explicitly.我有一个任务,我只知道数组的长度,需要转换项目。
我想做这样的事情:
快速创建这样的数组:
但它不起作用,因为:
(请参阅 Jonathan Lonowski 的回答)
解决方案可能是使用 Array.prototype.fill()
更新
另一种解决方案可能是:
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:
To quickly create an array like this:
But it didn't work because:
(see Jonathan Lonowski's answer)
The solution could be to fill up the array items with any value (even with undefined) using Array.prototype.fill()
Update
Another solution could be: