提问人:rampion 提问时间:3/31/2011 最后编辑:user3840170rampion 更新时间:4/14/2023 访问量:102441
为什么“map”方法显然不适用于通过“new Array(count)”创建的数组?
Why does the `map` method apparently not work on arrays created via `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)
答:
看来第一个例子
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 = [,,,];
由于 map 在索引/属性列表上运行,而不是在设置的长度上运行,因此如果没有创建索引/属性,它将不会运行。
评论
callback
仅对具有赋值的数组索引调用;对于已删除或从未赋值的索引,不会调用它。在本例中,的值没有显式赋值,而 的值是赋值的,即使它是值 。map
x
y
undefined
(new Array(1))[0] === [undefined][0]
hasOwnProperty
hasOwnProperty
(new Array(1)).hasOwnProperty(0) === false
[undefined].hasOwnProperty(0) === true
in
0 in [undefined] === true
0 in new Array(0) === false
x = new Array(3);
x = [,,,];
x = [undefined, undefined, undefined]
不是错误。这就是定义 Array 构造函数的工作方式。
来自 MDC:
使用 Array 构造函数指定单个数值参数时,将指定数组的初始长度。下面的代码创建一个包含五个元素的数组:
var billingMethod = new Array(5);
Array 构造函数的行为取决于单个参数是否为数字。
该方法仅在数组的迭代元素中包含已显式分配了值的元素。即使是显式赋值也会导致值被视为有资格包含在迭代中。这看起来很奇怪,但它本质上是对象上的显式属性和缺失属性之间的区别:.map()
undefined
undefined
var x = { }, y = { z: undefined };
if (x.z === y.z) // true
该对象没有名为“z”的属性,而该对象有。但是,在这两种情况下,属性的“值”似乎都是 。在数组中,情况类似:的值 does 隐式地对从 0 到 的所有元素执行值赋值。因此,当对使用 Array 构造函数和数值参数新构造的数组进行调用时,该函数不会执行任何操作(不会调用回调)。x
y
undefined
length
length - 1
.map()
评论
undefined
x = []
x = new Array()
从地图
的 MDC 页面:
[...] 仅对具有赋值的数组索引调用;[...]
callback
[undefined]
实际上在索引上应用 setter,以便迭代,而仅使用默认值 so 初始化索引会跳过它。map
new Array(1)
undefined
map
我相信这对于所有迭代方法都是一样的。
我认为解释这一点的最好方法是查看 Chrome 处理它的方式。
>>> x = new Array(3)
[]
>>> x.length
3
因此,实际发生的是 new Array() 返回一个长度为 3 但没有值的空数组。因此,当您在技术上为空的数组上运行时,无需设置任何内容。x.map
Firefox只是“填充”了这些空槽,即使它没有值。undefined
我不认为这显然是一个错误,只是一种表达正在发生的事情的糟糕方式。我认为 Chrome 的“更正确”,因为它表明数组中实际上没有任何内容。
数组是不同的。区别在于,创建一个长度为 3 但没有属性的数组,而创建一个长度为 3 的数组,以及名为“0”、“1”和“2”的三个属性,每个属性的值为 。您可以使用运算符查看差异:new Array(3)
[undefined, undefined, undefined]
undefined
in
"0" in new Array(3); // false
"0" in [undefined, undefined, undefined]; // true
这源于一个有点令人困惑的事实,即如果你试图获取 JavaScript 中任何本机对象的不存在属性的值,它会返回(而不是抛出错误,就像你尝试引用不存在的变量时发生的那样),这与你得到的相同,如果该属性之前被显式设置为 .undefined
undefined
刚刚遇到了这个。能够使用肯定会很方便。Array(n).map
Array(3)
产量大致{length: 3}
[undefined, undefined, undefined]
创建编号属性:
。{0: undefined, 1: undefined, 2: undefined, length: 3}
map() 实现仅作用于定义的属性。
我有一个任务,我只知道数组的长度,需要转换项目。 我想做这样的事情:
let arr = new Array(10).map((val,idx) => idx);
要快速创建如下所示的数组,请执行以下操作:
[0,1,2,3,4,5,6,7,8,9]
但它没有奏效,因为: (参见乔纳森·洛诺夫斯基的回答)
解决方案可能是使用 Array.prototype.fill() 用任何值(即使有 undefined)填充数组项
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));
评论
undefined
.fill()
let arr = new Array(10).fill().map((val,idx) => idx);
Array.from(Array(10))
Array.apply(null, Array(10)).map(() => { return {}; });
如果你这样做是为了轻松地用值填充数组,由于浏览器支持的原因不能使用 fill,并且真的不想做一个 for 循环,你也可以这样做,这将给你一个空字符串数组。x = new Array(3).join(".").split(".").map(...
我不得不说很丑陋,但至少问题和意图传达得很清楚。
使用 ES6,您可以做到,快速而简单![...Array(10)].map((a, b) => a)
评论
new Array(10).fill()
[...Array(10)]
[...Array(10).keys()]
在 ECMAScript 第 6 版规范中。
new Array(3)
只定义属性,而不定义索引属性,如 .请参阅 https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array-len 步骤 9。length
{length: 3}
[undefined, undefined, undefined]
将定义索引属性和长度属性,如 .请参阅 https://www.ecma-international.org/ecma-262/6.0/index.html#sec-runtime-semantics-arrayaccumulation 步骤 5。{0: undefined, 1: undefined, 2: undefined, length: 3}
ElementList
Array 的方法 , , , , 将通过内部方法检查 index 属性,因此不会调用回调。map
every
some
forEach
slice
reduce
reduceRight
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);
ES6 解决方案:
[...Array(10)]
不过,不适用于打字稿 (2.3)
评论
Array(10).fill("").map( ...
是 Typescript 2.9 对我有用的东西
下面是一个简单的实用方法作为解决方法:
简单地图用于
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]
既然问题是为什么,这与JS的设计方式有关。
我能想到的两个主要原因来解释这种行为:
性能:给定,构造函数避免从 0 到 10000 循环以用值填充数组是明智的。
x = 10000
new Array(x)
undefined
隐式“未定义”:Give 和 ,并且都将返回 ,但 和 即使超出范围,也会返回。
a = [undefined, undefined]
b = new Array(2)
a[1]
b[1]
undefined
a[8]
b[8]
undefined
归根结底,表示法是一种快捷方式,可以避免设置和显示一长串值,这些值无论如何都是,因为它们没有显式声明。empty x 3
undefined
undefined
注意:给定数组 和 ,将返回 ,通过返回显式声明的两个值之间的差值自动填充空白。a = [0]
a[9] = 9
console.log(a)
(10) [0, empty x 8, 9]
由于在其他答案中彻底解释的原因,不起作用。但是,在 ES2015 中,Array.from
接受映射函数:Array(n).map
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
评论
var y = x.map(function(){return 0; });