代码之家  ›  专栏  ›  技术社区  ›  rPat

JavaScript.apply方法是如何工作的?

  •  8
  • rPat  · 技术社区  · 9 年前

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

    但是,当apply调用调用它的函数时,它究竟是如何将一个参数数组传递给一个函数的,而这个函数并没有被编写为将一个数组作为参数?它是否将给定的参数数组与调用的函数“arguments”组合起来?

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

    欢迎任何解释。我对JavaScript是新手,想更好地了解幕后的情况。我目前正在尝试自己重新创建一些基本功能,这给我带来了很多麻烦。

    3 回复  |  直到 9 年前
        1
  •  5
  •   t3dodson    8 年前

    spec .

    我们必须获取argArray并创建arguments对象伪数组。

    基本上

    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 .

        2
  •  2
  •   Don Rhummy    9 年前

    它究竟是如何将一个参数数组传递到一个函数中的,而该函数并没有被编写为将一个数组作为参数

    你误解了这是如何工作的。 apply 向对象传递一个参数数组。它 一个数组,然后使用它动态构建函数调用,类似于您可以使用 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 .

        3
  •  0
  •   Piper McCorkle    9 年前

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

    "Source code" of <code>Function.prototype.apply</code>
    的“源代码” 功能.prototype.apply 根据 Function.prototype.toString 在V8中

    *假设JS引擎是用C编写的。替换为任何语言<在此处插入JS引擎>写入。