Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does function.apply.bind work in the following code?

So I get that an array of [200,599] is returned from the promise and the callback function inside spread is being passed into Function.apply.bind, but now I'm lost. How is the array of [200,599] split into x and y? How exactly does the apply.bind work?

function getY(x) {
        return new Promise( function(resolve,reject){
            setTimeout( function(){
                resolve( (3 * x) - 1 );
            }, 100 );
        } );
    }

function foo(bar,baz) {
    var x = bar * baz;

    // return both promises
    return [
        Promise.resolve( x ),
        getY( x )
    ];
}

function spread(fn) {
    return Function.apply.bind( fn, null );
}

Promise.all(
    foo( 10, 20 )
)
.then(
    spread( function(x,y){
        console.log( x, y );    // 200 599
    } )
)
like image 732
Gwater17 Avatar asked Oct 06 '16 22:10

Gwater17


2 Answers

.apply() is a method on function objects. Like so:

console.log(Math.max.apply(null, [1, 2, 3])); // 3

.apply() accepts two arguments, the context (what would become this inside of the target function) and an iterable of arguments (usually an array, but the arguments array like also works).


.bind() is a method on function objects. Like so:

const x = {
  foo: function() {
    console.log(this.x);
  },
  x: 42
}

var myFoo = x.foo.bind({x: 5});

x.foo(); // 42
myFoo(); // 5

.bind() takes a context (what would become this), and optionally, additional arguments, and returns a new function, with the context bound, and the additional arguments locked


Since .apply() is a function in on itself, it can be bound with .bind(), like so:

Function.prototype.apply.bind(fn, null);

Meaning that the this of .apply() would be fn and the first argument to .apply() would be null. Meaning that it would look like this:

fn.apply(null, args)

Which would spread the parameters from an array.

like image 81
Madara's Ghost Avatar answered Oct 13 '22 12:10

Madara's Ghost


Spread takes a function and binds the apply method to, partially applying the null argument. So in short,

spread(fn)

is transformed to

args => fn.apply(null, args)

which is the same as using the ES6 spread syntax

args => fn(...args)

where the function got its name from.


If you want the long answer, remember what bind does:

method.bind(context, ...args1)

returns a function that works like

(...args2) => method.call(context, ...args1, ...args2)

In our case, method is apply, the context is fn and the first arguments are null, so the call

Function.apply.bind( fn, null )

will create a function that works like

(...args2) => (Function.apply).call(fn, null, ...args2)

which is equivalent to the fn.apply(…) call above, given that apply is the method inherited from Function.prototype in both accesses.

like image 34
Bergi Avatar answered Oct 13 '22 12:10

Bergi