【发布时间】:2012-01-29 08:54:57
【问题描述】:
任何人都可以解释上下文以在 Javascript 中使用 call 和 apply 方法吗?
为什么要使用call和apply而不是直接调用函数?
【问题讨论】:
-
This read 在调用
apply()和call()时帮助我理解了thisArg的意义,这似乎是您问题的核心。您需要了解 Javascript 中的函数调用原语
标签: javascript
任何人都可以解释上下文以在 Javascript 中使用 call 和 apply 方法吗?
为什么要使用call和apply而不是直接调用函数?
【问题讨论】:
apply() 和call() 时帮助我理解了thisArg 的意义,这似乎是您问题的核心。您需要了解 Javascript 中的函数调用原语
标签: javascript
当您想将不同的this 值传递给函数时,您可以使用call 或apply。从本质上讲,这意味着您希望像执行特定对象的方法一样执行函数。两者的唯一区别是call 需要用逗号分隔的参数,而apply 需要数组中的参数。
来自Mozilla's apply page 的示例,其中构造函数是链式的:
function Product(name, price) {
this.name = name;
this.price = price;
if (price < 0)
throw RangeError('Cannot create product "' + name + '" with a negative price');
return this;
}
function Food(name, price) {
Product.apply(this, arguments);
this.category = 'food';
}
Food.prototype = new Product();
function Toy(name, price) {
Product.apply(this, arguments);
this.category = 'toy';
}
Toy.prototype = new Product();
var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);
Product.apply(this, arguments) 的作用如下:Product 构造函数在Food 和Toy 构造函数中作为函数应用,并且每个对象实例都作为this 传递。因此,Food 和 Toy 现在都具有 this.name 和 this.category 属性。
【讨论】:
Toy.prototype = new Product();?我对此进行了测试,删除这些行似乎对最终结果没有影响。
Toy.prototype = new Product();,但留下了Food.prototype = new Product();,所以现在 Food 继承自 Product,但 Toy 没有。我还在Product的prototype中添加了一个方法,从Food和Toy调用,让继承的缺失更加明显(打开控制台运行代码,Food可以调用Product继承的方法,但是Toy不能调用,会报错) .
【讨论】:
obj.whatever();语法,它可能引用调用者obj。
当您想要使函数以不同的this 值执行时,您可以使用.call()。它按指定设置this 值,按指定设置参数,然后调用该函数。 .call() 和仅仅执行函数的区别在于函数执行时this 指针的值。当您正常执行该函数时,javascript 决定 this 指针将是什么(通常是全局上下文 window,除非该函数作为对象上的方法调用)。当您使用.call() 时,您可以准确指定您希望将this 设置为什么。
当您要传递给函数的参数位于数组中时,您可以使用.apply()。 .apply() 还可以使函数以特定的 this 值执行。当您有不确定数量的来自其他来源的参数时,最常使用.apply()。它也经常使用特殊的局部变量 arguments 将参数从一个函数调用传递到另一个函数调用,其中包含传递给当前函数的一组参数。
【讨论】:
如果您有使用过 jQuery 的经验,您就会知道大多数函数都使用 this 对象。例如,collection.each(function() { ... });
在这个函数内部,"this" 指的是迭代器对象。这是一种可能的用法。
我个人使用.apply() 来实现请求队列 - 我将一组参数推送到队列中,当需要执行它时,我获取一个元素,并将其作为处理程序的参数传递函数使用.apply(),因此如果必须将参数数组作为第一个参数传递,则代码会更清晰。这是另一个例子。
一般来说,只要记住这些调用函数的方法是存在的,你可能有一天会发现它们很方便用于实现你的程序。
【讨论】:
如果您有使用Object Oriented Programming 的经验,那么如果您将其与继承进行比较并从子类覆盖父类的属性或方法/函数,那么调用和应用将是有意义的。这与 javascript 中的调用类似,如下所示:
function foo () {
this.helloworld = "hello from foo"
}
foo.prototype.print = function () {
console.log(this.helloworld)
}
foo.prototype.main = function () {
this.print()
}
function bar() {
this.helloworld = 'hello from bar'
}
// declaring print function to override the previous print
bar.prototype.print = function () {
console.log(this.helloworld)
}
var iamfoo = new foo()
iamfoo.main() // prints: hello from foo
iamfoo.main.call(new bar()) // override print and prints: hello from bar
【讨论】:
我想不出任何正常情况下将 thisArg 设置为不同的值是使用 apply 的目的。
apply 的目的是将值数组传递给希望这些值作为参数的函数。
它已被散布运算符取代为所有日常使用。
例如
// Finding the largest number in an array
`Math.max.apply(null, arr)` becomes `Math.max(...arr)`
// Inserting the values of one array at the start of another
Array.prototype.unshift.apply(arr1, arr2);
// which becomes
arr1 = [...arr2, ...arr1]
【讨论】: