我经常在JavaScript中看到以下类似的代码:
$("#sendButton").click(function() {
sendForm();
}
为什么需要将对
sendForm()
的调用封装在一个函数中?我认为这样做会更易读且少打字。$("#sendButton").click(sendForm);
每种方法都有优缺点,谢谢!
我经常在JavaScript中看到以下类似的代码:
$("#sendButton").click(function() {
sendForm();
}
sendForm()
的调用封装在一个函数中?我认为这样做会更易读且少打字。$("#sendButton").click(sendForm);
通常有两种情况需要使用前者而不是后者:
如果你需要在调用函数之前对参数进行任何后处理。
如果你正在调用对象的方法,则如果使用第二种形式,作用域(this引用)将会不同。
例如:
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
this
的值,即进入sendForm
的范围。 (参数也不同。)让我解释一下。sendForm();
会使用没有上下文对象的函数。这是JavaScript赋予的。$(...).click(sendForm)
,您只需传递对该函数的引用以供稍后调用。您现在还没有调用该函数,只是像对象引用一样传递它。只有在跟随它们的()
(除了稍后讨论的call
和apply
)时,才会调用函数。无论如何,如果某人最终调用此函数,则该人可以选择要使用的范围来调用该函数。$(...).click()
时,jQuery将稍后调用该函数并将作用域(this)设置为单击事件的HTML元素目标。您可以尝试一下:$(...).click(function() { alert(this); });
,将得到表示HTML元素的字符串。sendForm()
,则jQuery将在调用该函数时设置作用域,并且该函数将调用没有范围的sendForm
。实质上,它将清除this
。试一试:$(...).click(function() { (function() { alert(this); })(); });
。在这里,我们有一个匿名函数调用另一个匿名函数。我们需要在内部匿名函数周围加上括号,以便()应用于该函数。sendForm
的命名函数的引用,则jQuery将直接调用此函数并给出其承诺始终给出的作用域。this
指向单击开始工作时的元素目标,请使用.click(sendForm)
。否则,两者都同样有效。您可能不需要this
,因此跳过匿名函数即可。apply
或call
(请参见此处以了解两者之间的区别)来强制范围。当使用点运算符时,如:obj.func
,作用域也会被分配,这要求JavaScript将一个函数调用中的this
指向obj
。(因此理论上您可以通过执行以下操作来强制obj
成为调用函数时的作用域:obj.foo =(对函数的引用); obj.foo(); delete obj.foo;
但这是一种相当丑陋的使用方式。)apply
由jQuery用于具有范围的调用单击处理程序,还可以在函数调用中强制参数,并且实际上jQuery确实将参数传递给其单击处理程序。因此,两种情况之间还存在另一个区别:当您从匿名函数中调用sendForm
并不传递参数时,不仅作用域而且参数也会丢失。在这里,您正在定义一个匿名事件处理程序,它可以调用多个内联函数。这很不规范且难以调试,但人们这样做是因为他们懒惰并且能够这样做。
它也可以像您第二个示例(我如何定义事件处理程序)一样工作:
$("#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");
});
如果你只是调用 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
本身。这只是为了锁定作用域。当您将sendForm()
包装在闭合当前作用域的匿名函数中时,换句话说,this
将与其一起保留。如果您只传递sendForm
,则对this
的任何调用都将来自调用作用域。
这是一个学习JavaScript作用域和质疑惯例的好问题。
不,第二个例子是完全有效的。
99.9%的jQuery示例使用第一种符号表示法,但这并不意味着您需要忘记基本的JavaScript语法。
this
的值将不同(除非sendForm
是一个绑定函数),尽管第一个版本中的this
并不是很有用。 - the system