Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the JavaScript .apply method work?

I'm not asking how to use it. I know how to use it.

But when apply invokes the function that called it, how exactly does it pass an array of arguments into a function that was not written to take an array for an argument? Does it combine its given arguments array with the called functions "arguments"?

I looked at the latest ECMAscript specifications for .apply and .call, but I didn't really see anything about underlying logic.

Any explanation would be welcome. I'm new to JavaScript, and want to better understand what's going on under the hood. I'm currently trying to recreate some of the basic functions on my own, and this one is giving me a lot of trouble.

like image 985
rPat Avatar asked Jan 15 '16 01:01

rPat


People also ask

What is the difference between call () and apply () methods?

The Difference Between call() and apply() The difference is: The call() method takes arguments separately. The apply() method takes arguments as an array. The apply() method is very handy if you want to use an array instead of an argument list.

Why do we use the Bind method in JavaScript?

We use the Bind() method to call a function with the this value, this keyword refers to the same object which is currently selected . In other words, bind() method allows us to easily set which object will be bound by the this keyword when a function or method is invoked.

What is call apply bind method in JavaScript?

In JavaScript, you can use call() , apply() , and bind() methods to couple a function with an object. This way you can call the function on the object as if it belonged to it. The call() and apply() are very similar methods. They both execute the bound function on the object immediately.

What is function () )() in JavaScript?

It's an Immediately-Invoked Function Expression, or IIFE for short. It executes immediately after it's created. It has nothing to do with any event-handler for any events (such as document. onload ). Consider the part within the first pair of parentheses: (function(){})(); ....it is a regular function expression.


2 Answers

From the spec.

We have to take the argArray and create what will be the arguments object pseudo array.

Essentially

Function.prototype.apply = function apply (thisArg, argArray) {
    var len = argArray.length;
    var n = ToUint32(len);
    var argList = []; // where this is a List not an array.
    var index = 0;
    var indexName;
    var nextArg;
    while (index < len) {
        indexName = ToString(index);
        nextArg = argArray[indexName];
        argList.push(nextArg);
        index++;
    }
    return this['[[Call]]'](func, thisArg, argList); // ignore the syntax however
                                                     // This is the line where the function
                                                     // will be called and provide 
                                                     // the thisArg and thisArray
}

I omitted some of the type checking that happens but this is essentially pretty close to what the spec dictates as how Function.prototype.apply is implemented. We craft our own object and build up the argList prior to calling the function.

Its important to note. that the internal method named [[Call]] is different than Function.prototype.call.

like image 193
t3dodson Avatar answered Oct 04 '22 12:10

t3dodson


how exactly does it pass an array of arguments into a function that was not written to take an array for an argument

You are misunderstanding how this works. apply does not pass an array of arguments to the object. It takes an array and then uses that to dynamically build a function call, similarly to what you could do with an eval statement (but it does it natively).

For example, an eval statement could work like this:

function buildFromArray(funcName, arrayOfArgs)
{
    var functionCall = funcName + "(";

    for ( var i = 0; i < arrayOfArgs.length; i++ )
    {
        //Very simplified, only allows for string args
        functionCall += "\"" + arrayOfArgs + "\"";

        if ( i < arrayOfArgs.length - 1 ) functionCall += ",";
    }

    functionCall += ")";

    //Now we run the compiled call which will be something like:
    //myFunction("one","two")
    eval( functionCall );
}

buildFromArray( "myFunction", [ "one", "two" ] );

This is very simplified, but you can see how an array is never passed to the function myFunction.

like image 35
Don Rhummy Avatar answered Oct 04 '22 12:10

Don Rhummy