JavaScript .apply 方法如何工作?
How does the JavaScript .apply method work?
我不是问如何使用它。我知道怎么用了。
但是,当 apply 调用调用它的函数时,它究竟是如何将参数数组传递到一个函数中的,而这个函数并不是为了将数组作为参数而编写的?它是否将其给定的参数数组与调用的函数组合 "arguments"?
我查看了 .apply 和 .call 的最新 ECMAscript 规范,但我并没有真正看到任何关于底层逻辑的内容。
欢迎任何解释。我是 JavaScript 的新手,想更好地了解引擎盖下发生的事情。我目前正在尝试自己重新创建一些基本功能,而这个给我带来了很多麻烦。
Function.prototype.apply
是 implementation-specific:它是在 JavaScript 引擎本身中实现的。真的没有办法复制它,因为当你调用它时它使用 C* API 告诉引擎调用你想调用的函数。用户代码无法操作内部 API,因此没有本机代码就无法实现 Function.prototype.apply
。
"Source code" of Function.prototype.apply
根据 V8 中的 Function.prototype.toString
* 假设一个用 C 编写的 JS 引擎。替换为任何语言 是用什么语言编写的。
来自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
。
how exactly does it pass an array of arguments into a function that was not written to take an array for an argument
您误解了它的工作原理。 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
。
我不是问如何使用它。我知道怎么用了。
但是,当 apply 调用调用它的函数时,它究竟是如何将参数数组传递到一个函数中的,而这个函数并不是为了将数组作为参数而编写的?它是否将其给定的参数数组与调用的函数组合 "arguments"?
我查看了 .apply 和 .call 的最新 ECMAscript 规范,但我并没有真正看到任何关于底层逻辑的内容。
欢迎任何解释。我是 JavaScript 的新手,想更好地了解引擎盖下发生的事情。我目前正在尝试自己重新创建一些基本功能,而这个给我带来了很多麻烦。
Function.prototype.apply
是 implementation-specific:它是在 JavaScript 引擎本身中实现的。真的没有办法复制它,因为当你调用它时它使用 C* API 告诉引擎调用你想调用的函数。用户代码无法操作内部 API,因此没有本机代码就无法实现 Function.prototype.apply
。
"Source code" of Function.prototype.apply
根据 V8 中的 Function.prototype.toString
* 假设一个用 C 编写的 JS 引擎。替换为任何语言
来自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
。
how exactly does it pass an array of arguments into a function that was not written to take an array for an argument
您误解了它的工作原理。 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
。