为什么“map”方法显然不适用于通过“new Array(count)”创建的数组?

发布于 2024-10-28 03:51:23 字数 627 浏览 1 评论 0原文

我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

电影里的梦 2024-11-04 03:51:25

这是一个简单的实用方法作为解决方法:

Simple mapFor

function mapFor(toExclusive, callback) {
    callback = callback || function(){};
    var arr = [];
    for (var i = 0; i < toExclusive; i++) {
        arr.push(callback(i));
    }
    return arr;
};

var arr = mapFor(3, function(i){ return i; });
console.log(arr); // [0, 1, 2]
arr = mapFor(3);
console.log(arr); // [undefined, undefined, undefined]

完整示例

这是一个更完整的示例(带有健全性检查),它还允许指定可选的起始索引:

function mapFor() {
var from, toExclusive, callback;
if (arguments.length == 3) {
    from = arguments[0];
    toExclusive = arguments[1];
    callback = arguments[2];
} else if (arguments.length == 2) {
    if (typeof arguments[1] === 'function') {
        from = 0;
        toExclusive = arguments[0];
        callback = arguments[1];
    } else {
        from = arguments[0];
        toExclusive = arguments[1];
    }
} else if (arguments.length == 1) {
    from = 0;
    toExclusive = arguments[0];
}

callback = callback || function () {};

var arr = [];
for (; from < toExclusive; from++) {
    arr.push(callback(from));
}
return arr;
}

var arr = mapFor(1, 3, function (i) { return i; });
console.log(arr); // [1, 2]
arr = mapFor(1, 3);
console.log(arr); // [undefined, undefined]
arr = mapFor(3);
console.log(arr); // [undefined, undefined, undefined]

倒计时

操作传递给回调的索引可以倒数:

var count = 3;
var arr = arrayUtil.mapFor(count, function (i) {
    return count - 1 - i;
});
// arr = [2, 1, 0]

Here's a simple utility method as a workaround:

Simple mapFor

function mapFor(toExclusive, callback) {
    callback = callback || function(){};
    var arr = [];
    for (var i = 0; i < toExclusive; i++) {
        arr.push(callback(i));
    }
    return arr;
};

var arr = mapFor(3, function(i){ return i; });
console.log(arr); // [0, 1, 2]
arr = mapFor(3);
console.log(arr); // [undefined, undefined, undefined]

Complete Example

Here's a more complete example (with sanity checks) which also allows specifying an optional starting index:

function mapFor() {
var from, toExclusive, callback;
if (arguments.length == 3) {
    from = arguments[0];
    toExclusive = arguments[1];
    callback = arguments[2];
} else if (arguments.length == 2) {
    if (typeof arguments[1] === 'function') {
        from = 0;
        toExclusive = arguments[0];
        callback = arguments[1];
    } else {
        from = arguments[0];
        toExclusive = arguments[1];
    }
} else if (arguments.length == 1) {
    from = 0;
    toExclusive = arguments[0];
}

callback = callback || function () {};

var arr = [];
for (; from < toExclusive; from++) {
    arr.push(callback(from));
}
return arr;
}

var arr = mapFor(1, 3, function (i) { return i; });
console.log(arr); // [1, 2]
arr = mapFor(1, 3);
console.log(arr); // [undefined, undefined]
arr = mapFor(3);
console.log(arr); // [undefined, undefined, undefined]

Counting Down

Manipulating the index passed to the callback allows counting backwards:

var count = 3;
var arr = arrayUtil.mapFor(count, function (i) {
    return count - 1 - i;
});
// arr = [2, 1, 0]
骑趴 2024-11-04 03:51:24

看来第一个示例

x = new Array(3);

创建了一个长度为 3 但没有任何元素的数组,因此未创建索引 [0]、[1] 和 [2]。

第二个创建一个包含 3 个未定义对象的数组,在这种情况下,它们自己创建了索引/属性,但它们引用的对象未定义。

y = [undefined, undefined, undefined]
// The following is not equivalent to the above, it's the same as new Array(3)
y = [,,,];

由于映射在索引/属性列表上运行,而不是在设置的长度上运行,因此如果没有创建索引/属性,它将不会运行。

It appears that the first example

x = new Array(3);

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.

y = [undefined, undefined, undefined]
// The following is not equivalent to the above, it's the same as new Array(3)
y = [,,,];

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.

赢得她心 2024-11-04 03:51:24

使用 ES6,您可以快速轻松地执行 [...Array(10)].map((a, b) => a)

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

多孤肩上扛 2024-11-04 03:51:24

ES6 解决方案:

[...Array(10)]

但不适用于 typescript (2.3)

ES6 solution:

[...Array(10)]

Doesn't work on typescript (2.3), though

小帐篷 2024-11-04 03:51:24

来自 map

[...] callback 仅针对已分配值的数组索引调用; [...]

[undefined] 实际上将 setter 应用于索引,以便 map 进行迭代,而 new Array(1) 只是使用默认值 undefined 初始化索引,因此 map 会跳过它。

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

From the MDC page for map:

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

I believe this is the same for all iteration methods.

梨涡少年 2024-11-04 03:51:24

由于其他答案中彻底解释的原因, Array(n).map 不起作用。但是,在 ES2015 中 Array.from 接受一个地图函数:

let array1 = Array.from(Array(5), (_, i) => i + 1)
console.log('array1', JSON.stringify(array1)) // 1,2,3,4,5

let array2 = Array.from({length: 5}, (_, i) => (i + 1) * 2)
console.log('array2', JSON.stringify(array2)) // 2,4,6,8,10

For reasons thoroughly explained in other answers, Array(n).map doesn't work. However, in ES2015 Array.from accepts a map function:

let array1 = Array.from(Array(5), (_, i) => i + 1)
console.log('array1', JSON.stringify(array1)) // 1,2,3,4,5

let array2 = Array.from({length: 5}, (_, i) => (i + 1) * 2)
console.log('array2', JSON.stringify(array2)) // 2,4,6,8,10

芸娘子的小脾气 2024-11-04 03:51:24

数组不同。区别在于 new Array(3) 创建一个长度为 3 但没有属性的数组,而 [undefined, undefined, undefined] 创建一个长度为 3 的数组三个和三个属性分别称为“0”、“1”和“2”,每个属性的值为未定义。您可以使用 in 运算符看到差异:

"0" in new Array(3); // false
"0" in [undefined, undefined, undefined]; // true

这源于一个有点令人困惑的事实,即如果您尝试获取 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 of undefined. You can see the difference using the in operator:

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

请叫√我孤独 2024-11-04 03:51:24

在 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-arrayaccumulation ElementList 步骤 5.

方法 mapevery一些forEach切片reducereduceRight、 Array 的 filter 会通过 HasProperty 内部方法检查索引属性,因此 new Array(3).map(v => 1) 将不调用回调。

有关更多详细信息,请参阅 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);

In ECMAScript 6th edition specification.

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.

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

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.

for more detail, see 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);
秋凉 2024-11-04 03:51:24

我认为解释这一点的最好方法是看看 Chrome 处理它的方式。

>>> x = new Array(3)
[]
>>> x.length
3

所以实际发生的情况是 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.

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

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.

め七分饶幸 2024-11-04 03:51:24

不是错误。这就是数组构造函数的定义方式。

来自MDC:

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

var billingMethod = new Array(5);

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

.map() 方法仅包含已显式分配值的数组的迭代元素。即使显式分配 undefined 也会导致某个值被视为有资格包含在迭代中。这看起来很奇怪,但这本质上是对象上的显式 undefined 属性和缺失属性之间的区别:

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

对象 x 没有名为“z”的属性,并且对象 y 会这样做。然而,在这两种情况下,属性的“值”似乎都是未定义。在数组中,情况类似:length 的值确实隐式地对从 0 到 length - 1 的所有元素执行赋值。因此,当在使用 Array 构造函数和数字参数新构造的数组上调用时,.map() 函数不会执行任何操作(不会调用回调)。

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:

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.

凉城凉梦凉人心 2024-11-04 03:51:24

刚刚遇到这个。能够使用 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.

萌梦深 2024-11-04 03:51:24

如果您这样做是为了轻松地用值填充数组,则不能使用 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.

若有似无的小暗淡 2024-11-04 03:51:24

既然问题是为什么,这就和 JS 的设计方式有关。

我可以想到两个主要原因来解释这种行为:

  • 性能:给定 x = 10000new 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] = 9console.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 and new Array(x) it is wise for the constructor to avoid looping from 0 to 10000 to fill the array with undefined values.

  • Implicitly "undefined": Give a = [undefined, undefined] and b = new Array(2), a[1] and b[1] will both return undefined, but a[8] and b[8] will also return undefined even if they're out of range.

Ultimately, the notation empty x 3 is a shortcut to avoid setting and displaying a long list of undefined values that are undefined anyway because they are not declared explicitly.

Note: Given array a = [0] and a[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.

少钕鈤記 2024-11-04 03:51:23

我有一个任务,我只知道数组的长度,需要转换项目。
我想做这样的事情:

let arr = new Array(10).map((val,idx) => idx);

快速创建这样的数组:

[0,1,2,3,4,5,6,7,8,9]

但它不起作用,因为:
(请参阅 Jonathan Lonowski 的回答

解决方案可能是使用 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));

更新

另一种解决方案可能是:

let arr = Array.apply(null, Array(10)).map((val, idx) => idx);

console.log(Array.apply(null, Array(10)).map((val, idx) => idx));

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)

The solution could be to fill up the array items with any value (even with undefined) using 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));

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文