javascriptarraysecmascript-6ecma262

What's the principle of Array.apply(null, obj)?


let a = {0: 'a', 1: 'b', length: 2}
Array.apply(null, a) // ['a', 'b']

Using the Array constructor is the fastest way to convert an Array-like Object to Array e.g. jsperf

I want to figure out how it works but I failed. In ECMAScript-262, I can't find the corresponding approach to explain that code.

Why the Array constructor accept an array-like object can turn it to an Array.

Difference between Array.apply(null, Array(x) ) and Array(x)

Why does Array.apply(null, [args]) act inconsistently when dealing with sparse arrays?


Solution

  • When using Function#apply(), the second parameter takes an array-like. An array-like is basically an object that has numeric keys and a length property but isn't necessarily an array - for example the arguments object is an array-like.

    That parameter will then be supplied to the function you call apply on as if it is all the arguments for that function:

    function foo(one, two, three) {
      console.log("one:", one);
      console.log("two:", two);
      console.log("three:", three);
    }
    //normal invocation
    foo("hello", "world", "!");
    
    //.apply using an array-like
    foo.apply(null, {0: "nice", 1: "meeting", 2: "you", length: 3});
    
    //.apply using an array
    foo.apply(null, ["see", "you", "later"]);

    So, when you call Array.apply(null, {0: 'a', 1: 'b', length: 2}) that is equivalent to the call Array('a', 'b') - using the array constructor with multiple arguments produces an array from those arguments:

    console.log(Array("a", "b"));

    Thus when you call apply on the constructor function you get that behaviour.

    In ES6, passing an array as a second argument to .apply is almost the same as using the spread syntax:

    function foo(one, two, three) {
      console.log("one:", one);
      console.log("two:", two);
      console.log("three:", three);
    }
    
    const arrayArgs = ["hello", "world", "!"];
    foo(...arrayArgs);

    However, this doesn't work with array-likes:

    function foo(one, two, three) {
      console.log("one:", one);
      console.log("two:", two);
      console.log("three:", three);
    }
    
    const arrayLikeArgs = {0: "hello", 1: "world", 2: "!", length: 3};
    foo(...arrayLikeArgs);