为啥调用“应用”而不是直接调用函数?
Posted
技术标签:
【中文标题】为啥调用“应用”而不是直接调用函数?【英文标题】:Why invoke "apply" instead of calling function directly?为什么调用“应用”而不是直接调用函数? 【发布时间】:2011-08-21 15:38:08 【问题描述】:在查看 raphael 或 g.raphael 或其他库的源代码时,我注意到开发人员会这样做:
var val = Math.max.apply(Math, data_array);
为什么不直接调用函数呢,比如:
var val = Math.max(data_array);
谢谢。
【问题讨论】:
好的,所以我看到 Math.max 需要两个参数,所以我只是调用的示例 Math.max(array) 不起作用。所以,我想问题是我的问题中的第一行代码如何在 data_array 的每个元素上调用“max”? javascript 的.apply
和 .call
ftw!!
【参考方案1】:
通常您会使用apply()
和call()
来设置调用函数所属的上下文或对象。然后,该函数有效地成为该对象/上下文的方法,如果您需要访问上下文的字段,这将很有帮助。
这是 Javascript 原生调用函数的方式:
-
从参数 1 到末尾创建一个参数列表 (argList)
第一个参数是thisValue
将此设置为 thisValue 并将 argList 作为其参数列表来调用函数
参考:Understanding JavaScript Function Invocation and "this"Yehuda Katz
因此,当直接调用函数时,实际上是在隐式地将默认上下文传递给函数。当您未使用 call()
或 apply()
指定时,Javascript 将 'window'
或 'undefined'
作为上下文传递
answer 还提供了一个示例,可能有助于理解用法
【讨论】:
【参考方案2】:.apply
通常用于意图调用带有参数值列表的可变参数函数,例如
Math.max([value1[,value2, ...]])
函数返回零个或多个数字中的最大值。
Math.max(10, 20); // 20
Math.max(-10, -20); // -10
Math.max(-10, 20); // 20
Math.max()
方法不允许您传入数组。如果您有一个需要获取最大值的列表,您通常会使用Function.prototype.apply() 调用此函数,例如
Math.max.apply(null, [10, 20]); // 20
Math.max.apply(null, [-10, -20]); // -10
Math.max.apply(null, [-10, 20]); // 20
但是,从 ECMAScript 6 开始,您可以使用 spread operator:
扩展运算符允许在需要多个参数(用于函数调用)或多个元素(用于数组字面量)的地方扩展表达式。
Math.max(...[10, 20]); // 20
Math.max(...[-10, -20]); // -10
Math.max(...[-10, 20]); // 20
当使用可变参数调用函数时,你甚至可以添加额外的值,例如
Math.max(...[10, 20], 50); // 50
Math.max(...[-10, -20], 50); // 50
【讨论】:
【参考方案3】:为什么调用“apply”而不是直接调用函数?让我们来个sn-p:
var obj = a: "apply";
func.call(obj, "parameter");
function func(para)
if(this.a === "apply")
console.log('apply');
这里我们可以看到我们在一个函数中使用'this'
(上下文),如果我们直接调用一个函数而不是我们没有任何上下文,那么它将使用window
上下文,这是错误的。因此,如果您在函数中使用上下文而不是使用 apply
方法。
【讨论】:
【参考方案4】:我认为Mozilla Docs的解释描述得很好:
您可以分配不同的 this 对象 调用现有函数时。 this 指的是当前对象, 调用对象。通过应用,您可以 写一次方法然后继承 它在另一个对象中,没有 重写新的方法 对象。
apply 与 call 非常相似,除了 对于它支持的参数类型。 您可以改用参数数组 一组命名的参数。和 应用,您可以使用数组文字, 例如,fun.apply(this, [name, value]) 或 Array 对象,用于 例如,fun.apply(这个,新的 数组(名称,值))。
关于参数:
thisArg 确定 fun 中 this 的值。如果 thisArg 为 null 或 未定义,this 将是全局的 目的。否则,这将是相等的 到 Object(thisArg) (这是 thisArg 如果 thisArg 已经是一个对象,或者一个 如果 thisArg,则为字符串、布尔值或数字 是的原始值 对应类型)。因此它是 总是如此 typeof this == 函数执行时的“对象”。
argsArray 对象的参数数组,指定参数 fun 应该被调用,或者 null 或者 如果没有参数应该是未定义的 提供给函数。
文档提供了一个很好的应用用例示例。在下面的示例中,apply 用于链接构造函数:
function product(name, value)
this.name = name;
if (value >= 1000)
this.value = 999;
else
this.value = value;
function prod_dept(name, value, dept)
this.dept = dept;
product.apply(this, arguments);
prod_dept.prototype = new product();
// since 5 is less than 1000 value is set
var cheese = new prod_dept("feta", 5, "food");
// since 5000 is above 1000, value will be 999
var car = new prod_dept("honda", 5000, "auto");
请注意,在prod_dept
构造函数中,提供的this
引用prod_dept
对象,arguments
是传递给product
构造函数的参数数组。
【讨论】:
prod_dept.prototype = new product();
此行完全不需要,请排除复杂性!【参考方案5】:
Math.max 默认不接受列表。 "apply" 允许您将列表解压缩为参数,以便 max 正常工作。
【讨论】:
以上是关于为啥调用“应用”而不是直接调用函数?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我可以使用 SELECT 而不是 CALL 调用 HSQL 函数?
为啥 std::apply 可以调用 lambda 而不是等效的模板函数?
在渲染期间,为啥要在 React.createElement 中包装一个函数式组件,而不是通过函数调用来使用它返回的元素呢?