JavaScript .apply方法如何工作?

时间:2016-01-15 01:37:08

标签: javascript callback call apply

我不问如何使用它。我知道如何使用它。

但是当apply调用调用它的函数时,它究竟是如何将一个参数数组传递给一个未编写为参数的数组的函数?它是否将其给定的arguments数组与被调用的函数" arguments"?

组合在一起

我查看了.apply和.call的最新ECMAscript规范,但我并没有真正看到底层逻辑。

欢迎任何解释。我是JavaScript的新手,想要更好地了解幕后发生的事情。我现在正试图自己重新创建一些基本功能,而这个功能给我带来了很多麻烦。

3 个答案:

答案 0 :(得分:3)

来自spec

我们必须采用argArray并创建对象伪数组。

基本上

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
}

我省略了一些发生的类型检查,但这基本上非常接近规范所指示的Function.prototype.apply如何实现。我们制作自己的对象,并在调用函数之前构建argList

重要的是要注意。名为[[Call]]的内部方法与Function.prototype.call不同。

答案 1 :(得分:2)

  

它如何将一个参数数组传递给一个函数,该函数未被编写为参数的数组

你误解了它是如何工作的。 apply 将一个参数数组传递给该对象。它接受一个数组然后使用它来动态构建一个函数调用,类似于你可以用eval语句做的事情(但它本身就是这样)。

例如,eval语句可以这样工作:

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" ] );

这是非常简化的,但您可以看到数组永远不会传递给函数myFunction

答案 2 :(得分:0)

Function.prototype.apply是特定于实现的:它是在JavaScript引擎本身中实现的。实际上没有办法复制它,因为当你调用它时,它使用C * API来告诉引擎调用你想要调用的函数。用户代码无法操纵内部API,因此没有本机代码就无法实现Function.prototype.apply

"Source code" of <code>Function.prototype.apply</code>
根据V8中Function.prototype.apply的<{1>}

“源代码”

*假设一个用C语言编写的JS引擎。替换为任何语言&lt;在这里插入JS引擎&gt;是写的。