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:
With ES6, you can do [...Array(10)].map((a, b) => a)
, quick and easy!
ES6 solution:
[...Array(10)]
Doesn't work on typescript (2.3), though
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.
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]
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);
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.