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

时间:2013-01-06 22:52:54

标签: javascript

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

$("#sendButton").click(function() {
    sendForm();
}

为什么有必要在函数中包含对sendForm()的调用?我认为这样做会更具可读性,更少打字。

$("#sendButton").click(sendForm);

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

6 个答案:

答案 0 :(得分:5)

通常有两种情况你想要使用前者而不是后者:

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

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

  3. 例如:

    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();
    });
    

    控制台输出:

    undefined
    1
    

答案 1 :(得分:0)

不,第二个例子完全有效。

99.9%的jQuery示例使用第一种表示法,这并不意味着您需要忘记基本的JavaScript语法。

答案 2 :(得分:0)

在这里,您要定义一个可以内联调用多个函数的匿名事件处理程序。它很脏而且难以调试,但是人们这样做是因为它们很懒惰而且可以。

它也会像你的第二个例子(我如何定义事件处理程序)一样工作:

$("#sendButton").click(sendForm)

通过内联定义事件处理程序可以获得的功能是将事件数据传递给多个函数,并将this范围限定为事件对象:

$("#sendButton").click(function(event) {
    sendForm();
    doSomethingElse(event);
    andAnotherThing(event);
    // say #sendButton is an image or has some data attributes
    var myButtonSrc = $(this).attr("src");
    var myData = $(this).data("someData");
});

答案 3 :(得分:0)

如果您所做的只是调用sendForm,那么最后,您所包含的两个示例之间没有太大区别。

$("#sendButton").click(function(event) {
    if(event.someProperty) { /* ... */ }
    else { sendForm({data: event.target, important: 'yes'}); }
}

但是,在上面的例子中,我们可以处理从click()传递给回调的参数,但是如果sendForm函数已经配备来处理这个,那么就没有理由不将sendForm作为回调参数如果真的是你正在做的事情。

function sendForm(event) {
    // Do something meaningful here.
}

$("#sendButton").click(sendForm);

请注意,由您来处理程序中不同逻辑层的位置;您可能已在sendForm函数中封装了某些通用功能,然后将sendFormCallback传递给这些函数,这些函数在调用sendForm之前处理事件/回调处理的临时业务。

如果您在回调密集的环境中工作,最好将重要功能与回调触发器本身分开,以避免callback hell并提高源代码的可维护性和可读性。

答案 4 :(得分:0)

只是锁定范围。将sendForm()包装在关闭当前范围的匿名函数中时。换句话说,this将保留。如果您只是通过sendForm,那么对this的任何来电都将来自通话范围 这是学习javascript范围和提问惯例的好问题。

答案 5 :(得分:0)

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

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

但是,当您将函数作为参数传递时,如下所示:$(...).click(sendForm),您只需传递对该函数的引用以供以后调用。您尚未调用该函数,只是像对象引用一样传递它。只有当()跟随它们时才会调用函数(callapply除外,稍后讨论)。在任何情况下,如果有人最终调用此函数,那么有人可以选择调用该函数的范围。

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

因此,如果你给jQuery一个对sendForm()的匿名函数的引用,jQuery将在调用该函数时设置范围,然后该函数将调用sendForm而不用范围。从本质上讲,它将清除this。试一试:$(...).click(function() { (function() { alert(this); })(); });。在这里,我们有一个匿名函数调用匿名函数。我们需要围绕内部匿名函数的括号,以便()适用于函数。

如果您给jQuery一个对命名函数sendForm的引用,jQuery将直接调用此函数并为其提供它承诺始终给出的范围。

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

对于那些好奇的人,可以使用JavaScript标准applycallsee this来强制使用范围来实现两者之间的差异)。使用点运算符时也会分配范围,例如:obj.func,要求JavaScript调用指向this的{​​{1}}的函数。 (所以从理论上讲,你可以强制obj成为调用函数时的范围,例如:obj,但这是使用apply的一种非常丑陋的方式。

jQuery使用函数obj.foo = (reference to function); obj.foo(); delete obj.foo;来调用带有作用域的click处理程序,也可以在函数调用上强制执行参数,实际上jQuery会将参数传递给它的click处理程序。因此,这两种情况之间还存在另一个区别:参数,不仅是范围,当您从匿名函数调用apply并且不传递任何参数时会丢失。