開頭:各類緣由總結一下javascript中的自動執行函數(當即調用函數)的一些方法,正文以下javascript
在Javascript中,任何function在執行的時候都會建立一個執行上下文,由於function聲明變量和function有可能只在該function內部,這個上下文,在調用function的時候,提供一些簡單的方式來建立自由變量或私有子function。html
eg:java
// 因爲該function裏返回了另一個function,其中這個function能夠訪問自由變量i // 全部說,這個內部的function其實是有權限能夠調用內部的對象。 function makeCounter() { // 只能在makeCounter內部訪問i var i = 0; return function () { console.log(++i); }; } // 注意,counter和counter2是不一樣的實例,分別有本身範圍內的i。 var counter = makeCounter(); counter(); // logs: 1 counter(); // logs: 2 var counter2 = makeCounter(); counter2(); // logs: 1 counter2(); // logs: 2 alert(i); // 引用錯誤:i沒有defind(由於i是存在於makeCounter內部)。
正文核心
一、Javascript方法:
在聲明相似function foo(){}或var foo = function(){}函數的時候,經過在後面加個括弧就能夠實現自執行,例如foo(),看代碼:
// 由於想下面第一個聲明的function能夠在後面加一個括弧()就能夠本身執行了,好比foo(), // 由於foo僅僅是function() { /* code */ }這個表達式的一個引用 var foo = function(){ /* code */ } // ...是否是意味着後面加個括弧均可以自動執行? function(){ /* code */ }(); // SyntaxError: Unexpected token (上述代碼,若是甚至運行,第2個代碼會出錯,由於在解析器解析全局的function或者function內部function關鍵字的時候,默認是認爲function聲明,而不是function表達式,若是你不顯示告訴編譯器,它默認會聲明成一個缺乏名字的function,而且拋出一個語法錯誤信息,由於function聲明須要一個名字。 有趣的是,即使你爲上面那個錯誤的代碼加上一個名字,他也會提示語法錯誤,只不過和上面的緣由不同。在一個表達式後面加上括號(),該表達式會當即執行,可是在一個語句後面加上括號(),是徹底不同的意思,他的只是分組操做符。// 下面這個function在語法上是沒問題的,可是依然只是一個語句// 加上括號()之後依然會報錯,由於分組操做符須要包含表達式function foo(){ /* code */ }(); // SyntaxError: Unexpected token )// 可是若是你在括弧()裏傳入一個表達式,將不會有異常拋出// 可是foo函數依然不會執行function foo(){ /* code */ }( 1 );// 由於它徹底等價於下面這個代碼,一個function聲明後面,又聲明瞭一個毫無關係的表達式:function foo(){ /* code */ }( 1 );你能夠訪問ECMA-262-3 in detail. Chapter 5. Functions 獲取進一步的信息。要解決上述問題,很是簡單,咱們只須要用大括弧將代碼的代碼所有括住就好了,由於JavaScript裏括弧()裏面不能包含語句,因此在這一點上,解析器在解析function關鍵字的時候,會將相應的代碼解析成function表達式,而不是function聲明。// 下面2個括弧()都會當即執行(function () { /* code */ } ()); // 推薦使用這個(function () { /* code */ })(); // 可是這個也是能夠用的// 因爲括弧()和JS的&&,異或,逗號等操做符是在函數表達式和函數聲明上消除歧義的// 因此一旦解析器知道其中一個已是表達式了,其它的也都默認爲表達式了// 不過,請注意下一章節的內容解釋var i = function () { return 10; } ();true && function () { /* code */ } ();0, function () { /* code */ } ();// 若是你不在乎返回值,或者不怕難以閱讀// 你甚至能夠在function前面加一元操做符號!function () { /* code */ } ();~function () { /* code */ } ();-function () { /* code */ } ();+function () { /* code */ } ();// 還有一個狀況,使用new關鍵字,也能夠用,但我不肯定它的效率// http://twitter.com/kuvos/status/18209252090847232new function () { /* code */ }new function () { /* code */ } () // 若是須要傳遞參數,只須要加上括弧()上面所說的括弧是消除歧義的,其實壓根就不必,由於括弧原本內部原本指望的就是函數表達式,可是咱們依然用它,主要是爲了方便開發人員閱讀,當你讓這些已經自動執行的表達式賦值給一個變量的時候,咱們看到開頭有括弧(,很快就能明白,而不須要將代碼拉到最後看看到底有沒有加括弧。用閉包保存狀態
和普通function執行的時候傳參數同樣,自執行的函數表達式也能夠這麼傳參,由於閉包直接能夠引用傳入的這些參數,利用這些被lock住的傳入參數,自執行函數表達式能夠有效地保存狀態。
// 這個代碼是錯誤的,由於變量i歷來就沒背locked住// 相反,當循環執行之後,咱們在點擊的時候i纔得到數值// 由於這個時候i操真正得到值// 因此說不管點擊那個鏈接,最終顯示的都是I am link #10(若是有10個a元素的話) var elems = document.getElementsByTagName('a');for (var i = 0; i < elems.length; i++) { elems[i].addEventListener('click', function (e) { e.preventDefault();alert('I am link #' + i); }, 'false');}// 這個是能夠用的,由於他在自執行函數表達式閉包內部// i的值做爲locked的索引存在,在循環執行結束之後,儘管最後i的值變成了a元素總數// 但閉包內部的lockedInIndex值是沒有改變,由於他已經執行完畢了// 因此當點擊鏈接的時候,結果是正確的var elems = document.getElementsByTagName('a');
for (var i = 0; i < elems.length; i++) {(function (lockedInIndex) { elems[i].addEventListener('click', function (e) { e.preventDefault();alert('I am link #' + lockedInIndex); }, 'false');})(i); }// 你也能夠像下面這樣應用,在處理函數那裏使用自執行函數表達式// 而不是在addEventListener外部// 可是相對來講,上面的代碼更具可讀性var elems = document.getElementsByTagName('a');
for (var i = 0; i < elems.length; i++) { elems[i].addEventListener('click', (function (lockedInIndex) { return function (e) {e.preventDefault();alert('I am link #' + lockedInIndex);};})(i), 'false');}其實,上面2個例子裏的lockedInIndex變量,也能夠換成i,由於和外面的i不在一個做用於,因此不會出現問題,這也是匿名函數+閉包的威力。 自執行匿名函數和當即執行的函數表達式區別 在這篇帖子裏,咱們一直叫自執行函數,確切的說是自執行匿名函數(Self-executing anonymous function),但英文原文做者一直倡議使用當即調用的函數表達式(Immediately-Invoked Function Expression)這一名稱,做者又舉了一堆例子來解釋,好吧,咱們來看看:
// 這是一個自執行的函數,函數內部執行自身,遞歸
function foo() { foo(); }
// 這是一個自執行的匿名函數,由於沒有標示名稱
// 必須使用arguments.callee屬性來執行本身
var foo = function () { arguments.callee(); };
// 這可能也是一個自執行的匿名函數,僅僅是foo標示名稱引用它自身
// 若是你將foo改變成其它的,你將獲得一個used-to-self-execute匿名函數
var foo = function () { foo(); };
// 有些人叫這個是自執行的匿名函數(即使它不是),由於它沒有調用自身,它只是當即執行而已。 (function () { /* code */ } ());
// 爲函數表達式添加一個標示名稱,能夠方便Debug
// 但必定命名了,這個函數就再也不是匿名的了
(function foo() { /* code */ } ());
// 當即調用的函數表達式(IIFE)也能夠自執行,不過可能不經常使用罷了
(function () { arguments.callee(); } ()); (function foo() { foo(); } ());
// 另外,下面的代碼在黑莓5裏執行會出錯,由於在一個命名的函數表達式裏,他的名稱是undefined
(function foo() { foo(); } ());
但願這裏的一些例子,可讓你們明白,什麼叫自執行,什麼叫當即調用。jquery
注意:arguments.callee在ECMAScript 5 strict mode裏被廢棄了,因此在這個模式下,實際上是不能用的。瀏覽器
在JS中最簡單的調用方式,直接寫到html的body標籤裏面:
在JS中調用方式:閉包
二、JQ方法 ecmascript
1)整個頁面的document所有加載完成之後執行。不幸的這種方式不只要求頁面的DOM tree所有加載完成,並且要求全部的外部圖片和資源所有加載完成。更不幸的是,若是外部資源,例如圖片須要很長時間來加載,那麼這個js方法執行感受就比較慢了。也就是說這是一種最嚴謹的頁面加載完再執行方法的方法。 window.onload =function() { $("table tr:nth-child(even)").addClass("even"); //這個是jquery代碼 };函數
2)僅只須要加載全部的DOM結構,在瀏覽器把全部的HTML放入DOM tree以前就執行方法。包括在加載外部圖片和資源以前。 $(document).ready(function() { $("table tr:nth-child(even)").addClass("even"); //任何須要執行的js特效 });this
3)還有一種簡寫方式 $(function() { $("table tr:nth-child(even)").addClass("even"); //任何須要執行的js特效 });
參考: http://www.jb51.net/article/81724.htm
spa
http://blog.csdn.net/limlimlim/article/details/9198111http://www.cnblogs.com/ayning/p/4113314.html
<bodyonload="myfunction()"><html> <bodyonload="func1();func2();func3();"> </body> </html> <script type="text/javascript"> functionmyfun() { alert("this window.onload"); } /*用window.onload調用myfun()*/ window.onload = myfun;//不要括號 </script> <script type="text/javascript"> window.onload=function(){ func1(); func2(); func3(); } </script>