我經常看到類似JavaScript中的以下內容:爲什麼是必要的包裝函數調用的函數體
$("#sendButton").click(function() {
sendForm();
}
爲什麼要包裝一個函數中調用sendForm()
?我認爲這樣做會更具可讀性,輸入更少。
$("#sendButton").click(sendForm);
每種方法的優缺點是什麼?謝謝!
我經常看到類似JavaScript中的以下內容:爲什麼是必要的包裝函數調用的函數體
$("#sendButton").click(function() {
sendForm();
}
爲什麼要包裝一個函數中調用sendForm()
?我認爲這樣做會更具可讀性,輸入更少。
$("#sendButton").click(sendForm);
每種方法的優缺點是什麼?謝謝!
現在大概有一個答案太多了,但兩者的區別是this
的值,即範圍,輸入sendForm
。 (也有不同的論點。)讓我解釋一下。
根據JavaScript規範,調用如下函數:sendForm();
調用沒有上下文對象的函數。這是一個給定的JavaScript。
但是,當您將函數作爲參數傳遞時,如下所示:$(...).click(sendForm)
,只需將函數的引用傳遞給以後的調用即可。你現在還沒有調用這個函數,而只是簡單地將它傳遞給對象引用。如果()
跟隨它們,您只能調用函數(除了call
和apply
,稍後討論)。無論如何,如果有人最終調用此函數,那麼某人可以選擇調用該函數的範圍。
在我們的案例中,有人是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標準(用於兩個之間的差異see this)apply
或call
被迫。使用點運算符時也指定了範圍,如:obj.func
,它要求JavaScript調用指向obj
的this
的函數。 (所以理論上你可以強制obj
作爲調用某個函數的範圍,例如:obj.foo = (reference to function); obj.foo(); delete obj.foo;
,但這是一種使用apply的非常醜陋的方式。
函數apply
,由jQuery用於調用您的點擊處理程序與範圍,也可以強制在函數調用的參數,實際上jQuery確實將參數傳遞給它的點擊處理程序。因此,這兩種情況之間還有另一個區別:參數不僅僅是範圍,當您從匿名函數調用sendForm
並且不傳遞任何參數時,它們會丟失。
不,那第二個例子是完全有效的。
99.9%的jQuery示例使用第一種表示法,這並不意味着您需要忘記基本的JavaScript語法。
在這裏,您定義了一個匿名事件處理程序,可以調用多個函數內聯。調試很髒並且很難,但是人們這樣做是因爲他們很懶,而且他們可以。
這也將工作就像你的第二個例子(我如何定義事件處理程序):
$("#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");
});
通常會有兩種情況下,你想使用前者優於後者:
如果在調用函數之前需要對參數進行任何後處理。
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
如果你只是在打電話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並提高源代碼中的可維護性和可讀性將是明智之舉。
這只是鎖定範圍。當您將該sendForm()
包裝在關閉當前作用域的匿名函數中時。換句話說,this
將與它保持一致。如果您只通過sendForm
,則任何對this
的呼叫都將來自呼叫範圍。
這是一個很好的問題,可以學習JavaScript中的範圍和提問慣例。
這是沒有必要的,它可能是出於習慣。 – Musa
請記住,在您的兩個版本中'this'的值將有所不同(除非'sendForm'是一個綁定函數),但第一個版本中的this不是很有用。 –