JavaScript “new Array(n)” and “Array.prototype.map” weirdness
我在firefox-3.5.7/firebug-1.5.3和firefox-3.6.16/firebug-1.6.2中观察到了这一点。
当我启动Firebug时:
1 2 3 4 5 6 7 8 9 10 11 12 | >>> 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] |
这是怎么回事?这是一个bug,还是我误解了如何使用
第一个例子
1 | x = new Array(3); |
创建具有未定义指针的数组。
第二个创建一个带有指向3个未定义对象的指针的数组,在这种情况下,它们自己的指针不是未定义的,只有它们指向的对象。
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是在数组中对象的上下文中运行的,所以我相信第一个map在第二个map运行时根本无法运行函数。
我有一个任务,我只知道数组的长度,需要转换项目。我想这样做:
1 | let arr = new Array(10).map((val,idx) => idx); |
。
要快速创建这样的数组:
1 | [0,1,2,3,4,5,6,7,8,9] |
但它不起作用,因为:看乔纳森·洛诺夫斯基的回答,上面有几个答案。
解决方案可以是使用array.prototype.fill()用任何值(即使未定义)填充数组项
1 | let arr = new Array(10).fill(undefined).map((val,idx) => idx); |
。
1 | console.log(new Array(10).fill(undefined).map((val, idx) => idx)); |
更新
另一种解决方案可能是:
1 | let arr = Array.apply(null, Array(10)).map((val, idx) => idx); |
。
1 | console.log(Array.apply(null, Array(10)).map((val, idx) => idx)); |
号
有了ES6,你就可以轻松快捷地完成
ES6溶液:
1 | [...Array(10)] |
号
但不能在typescript(2.3)上工作
数组是不同的。区别在于,
1 2 | "0" in new Array(3); // false "0" in [undefined, undefined, undefined]; // true |
。
这源于一个稍微令人困惑的事实,即如果您试图获取javascript中任何本机对象的不存在属性的值,它将返回
从
[...]
callback is invoked only for indexes of the array which have assigned value; [...]
号
我相信这对于所有迭代方法都是一样的。
我认为最好的解释方法是看看Chrome处理它的方式。
1 2 3 4 | >>> x = new Array(3) [] >>> x.length 3 |
所以实际发生的是new array()返回的是一个长度为3但没有值的空数组。因此,当您在一个技术上为空的数组上运行
火狐只是用
我不认为这是一个明确的错误,只是一个糟糕的方式来表示正在发生的事情。我认为Chrome的"更正确",因为它表明数组中实际上没有任何内容。
在ECMAScript第6版规范中。
方法数组的
有关详细信息,请参阅https://www.ecma-international.org/ecma-262/6.0/index.html sec-array.prototype.map
如何修复?
1 2 3 4 5 6 7 8 9 10 11 | 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); |
刚刚碰到这个。使用
map()实现只对定义的属性起作用。
如果您这样做是为了方便地用值填充数组,由于浏览器支持的原因不能使用fill,并且确实不想执行for循环,那么您也可以执行
我不得不说得很难看,但至少问题和意图都清楚地传达了出来。
不是虫子。数组构造函数就是这样定义的。
来自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:
号
1 | var billingMethod = new Array(5); |
The behavior of the Array constructor depends on whether the single parameter is a number.
号
1 2 | var x = { }, y = { z: undefined }; if (x.z === y.z) // true |
。
对象
这里有一个简单的实用方法作为解决方法:
简单映射
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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] |
完整的例子
下面是一个更完整的示例(带有健全性检查),它还允许指定可选的起始索引:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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] |
。
倒计时
操作传递给回调的索引允许向后计数:
1 2 3 4 5 | var count = 3; var arr = arrayUtil.mapFor(count, function (i) { return count - 1 - i; }); // arr = [2, 1, 0] |
在Chrome中,如果我使用