what is Array.map(Function.call,Number)

前端 未结 4 1986
北荒
北荒 2021-02-06 01:36
var array1 = [1, 4, 9, 16];

map1=array1.map(Function.call,Number);

Why the output of map1 is [0,1,2,3], what this map function is doing?

4条回答
  •  隐瞒了意图╮
    2021-02-06 01:56

    Some Background

    Array.prototype.map takes two arguments: the first is a function which is called with each item in the array, the second, rarely-used argument is a this value which the first argument is called with. For example:

    [1,2,3].map(function() { return this.x; }, {x: 3}) // returns [3,3,3]
    

    Function.prototype.call is a function that is on all functions: (Function is itself a function, so Function.call is Function.prototype.call), which allows the function to be called with a specific this and a specific set of arguments (passed individually, not as an array in the case of Function.prototype.apply). For example:

    function someFunction(y) {
        return this + y;
    }
    someFunction.call(2, 3) // Returns 5, since this=2 and y=3
    

    But there's an extra detail in the real example, because it's not doing someFunction.call, it's doing Function.call: what's going on is Function.prototype.call is using this to determine what function gets called: if you rebind this, a different function gets called. You can rebind this with, well... Function.prototype.call.

    So this is equivalent to the previous example:

    function someFunction(y) {
        return this + y;
    }
    Function.call.call(someFunction, 2, 3)
    

    The second call to .call rebinds the first one, so that it invokes someFunction instead of Function, and passes it the arguments 2 and 3: it boils down to exactly someFunction.call(2, 3), which we've already seen.


    The Explanation

    Going back to the real example so we can put things together, we have

    [3,6,9].map(Function.call, Number)
    

    The second argument does binding, just like .call, so this is equivalent to:

    [3,6,9].map((...args) => Function.call.call(Number, ...args))
    

    which as we just saw, is equivalent to the more straight forward:

    [3,6,9].map((...args) => Number.call(...args))
    

    So, now, what are ...args? For each call, they're the item in the array, the position in the array, and the whole array. So really this expands to:

    [
        Number.call(3, 0, [3,6,9]),
        Number.call(6, 1, [3,6,9]),
        Number.call(9, 2, [3,6,9])
    ]
    

    Now remember, Number.call's first argument is this, while the other two arguments are provided to the function being called, Number. As far as I know, Number doesn't use this, so it essentially just throws the first argument away, so it's:

    [
        Number(0, [3,6,9]),
        Number(1, [3,6,9]),
        Number(2, [3,6,9])
    ]
    

    Number, only takes a single argument though, which it casts to a Number. That's trivial, though since it's argument already is a number. So that's how you get [1,2,3]. It's just the indexes, being needlessly cast to numbers, with a lot of function indirection.

提交回复
热议问题