为什么需要在函数体中包装函数调用

Jaj*_*ris 4 javascript

我经常在JavaScript中看到以下内容:

$("#sendButton").click(function() {
    sendForm();
}
Run Code Online (Sandbox Code Playgroud)

为什么有必要将调用包装到sendForm()函数内部?我认为这样做会更具可读性,更少打字.

$("#sendButton").click(sendForm);
Run Code Online (Sandbox Code Playgroud)

每种方法有哪些优点/缺点?谢谢!

Eva*_*oli 5

通常有两种情况,您希望使用前者而不是后者:

  1. 如果在调用函数之前需要对参数进行任何后处理.

  2. 如果要在对象上调用方法,则使用第二种形式时,范围(此引用)将不同

例如:

MyClass = function(){
    this.baz = 1;    
};

MyClass.prototype.handle = function(){
    console.log(this.baz);    
};

var o = new MyClass();

$('#foo').click(o.handle);
$('#foo').click(function(){
    o.handle();
});
Run Code Online (Sandbox Code Playgroud)

控制台输出:

undefined
1
Run Code Online (Sandbox Code Playgroud)


Mih*_*ila 2

现在可能答案太多了,但两者之间的区别在于 的值this,即范围,输入sendForm。(论点也不同。)让我解释一下。

根据 JavaScript 规范,调用这样的函数:sendForm();调用没有上下文对象的函数。这是给定的 JavaScript。

但是,当您将函数作为参数传递时,如下所示:$(...).click(sendForm),您只需传递对该函数的引用以供以后调用。您还没有调用该函数,而只是像对象引用一样传递它。仅当紧随其后时才调用函数( and()除外,稍后讨论)。无论如何,如果有人最终调用此函数,则该人可以选择调用该函数的作用域。callapply

在我们的例子中,这个人就是 jQuery。当您将函数传递给 时$(...).click(),jQuery 将稍后调用该函数并将范围 (this) 设置为单击事件的 HTML 元素目标。你可以尝试一下:$(...).click(function() { alert(this); });,会给你一个代表 HTML 元素的字符串。

因此,如果您给 jQuery 一个匿名函数的引用sendForm(),那么 jQuery 将在调用该函数时设置作用域,然后该函数将在sendForm没有作用域的情况下进行调用。本质上,它将清除this. 尝试一下:$(...).click(function() { (function() { alert(this); })(); });。在这里,我们有一个匿名函数调用另一个匿名函数。我们需要将内部匿名函数括起来,以便 () 适用于该函数。

相反,如果您为 jQuery 提供对命名函数的引用sendForm,jQuery 将直接调用该函数并为其提供它承诺始终提供的作用域。

因此,您的问题的答案现在变得更加明显:如果您this在开始工作时需要指向单击的元素目标sendForm,请使用.click(sendForm)。否则,两者都可以正常工作。您可能不需要this,因此跳过匿名函数。

apply对于那些好奇的人,可以通过使用 JavaScript 标准或call请参阅此处了解两者之间的差异)来强制范围。使用点运算符时也会分配作用域,例如:obj.func,它要求 JavaScript 调用this指向 的函数obj。(因此理论上,您可以obj通过执行以下操作强制成为调用函数时的作用域:obj.foo = (reference to function); obj.foo(); delete obj.foo;但这是使用 apply 的一种非常丑陋的方式。

jQuery 使用Functionapply来调用带有作用域的单击处理程序,它也可以在函数调用上强制使用参数,事实上 jQuery 确实将参数传递给它的单击处理程序。因此,这两种情况之间还有另一个区别:当您sendForm从匿名函数调用并且不传递任何参数时,参数(而不仅仅是作用域)会丢失。