JavaScript “new Array(n)” and “Array.prototype.map” weirdness

后端 未结 14 1914
粉色の甜心
粉色の甜心 2020-11-22 02:40

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:

相关标签:
14条回答
  • 2020-11-22 03:23

    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.

    0 讨论(0)
  • 2020-11-22 03:24

    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.

    0 讨论(0)
  • 2020-11-22 03:29

    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

    0 讨论(0)
  • 2020-11-22 03:33

    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.

    0 讨论(0)
  • 2020-11-22 03:34

    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.

    0 讨论(0)
  • 2020-11-22 03:36

    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.

    0 讨论(0)
提交回复
热议问题