我在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(函数(){返回0;}) ) // [undefined, undefined, undefined] console.log ( Y.map(函数(){返回0;}) ) // [0,0,0]

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


当前回答

在ECMAScript第6版规范。

new Array(3)只定义属性长度,不定义索引属性如{length: 3}。参见https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array-len步骤9。

[undefined, undefined, undefined]将定义索引属性和长度属性,如{0:undefined, 1: undefined, 2: undefined, length: 3}。参见https://www.ecma-international.org/ecma-262/6.0/index.html#sec-runtime-semantics-arrayaccumulation ElementList步骤5。

方法map, every, some, forEach, slice, 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

如何修复?

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

其他回答

如果你这样做是为了方便地用值填充数组,由于浏览器支持的原因不能使用fill,并且真的不想做for循环,你也可以执行x = new array (3).join(".").split(".").map(…它会给你一个空字符串数组。

我不得不说,这很难看,但至少问题和意图传达得很清楚。

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

我认为有两个主要原因可以解释这种行为:

性能:给定x = 10000和新Array(x),构造函数最好避免从0到10000循环填充未定义值的数组。 隐式"undefined":给定a = [undefined, undefined]和b = new Array(2), a[1]和b[1]都将返回undefined,但a[8]和b[8]即使超出范围也将返回undefined。

最终,符号empty x3是避免设置和显示一长串未定义值的快捷方式,因为它们没有显式声明。

注意:给定数组a =[0]和[9]= 9,console.log(a)将返回(10)[0,empty x 8,9],通过返回显式声明的两个值之间的差值自动填充空白。

在ES6中,您可以执行[…Array(10)]。地图((a, b) => a),快捷方便!

下面是一个简单的实用方法:

简单地图

函数mapFor(toExclusive, callback) { Callback = Callback || function(){}; Var arr = []; For (var I = 0;i < toExclusive;我+ +){ arr.push(回调(i)); } 返回arr; }; var arr = mapFor(3,函数(i){返回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]

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

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(新数组(10).fill(定义)。Map ((val, idx) => idx));

更新

另一个解决方案是:

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

console.log(数组。应用(null,数组(10))。Map ((val, idx) => idx));