Javascript 自動執行函數(立即調用函數)


開頭:各種原因總結一下javascript中的自動執行函數(立即調用函數)的一些方法,正文如下

    在Javascript中,任何function在執行的時候都會創建一個執行上下文,因為function聲明變量和function有可能只在該function內部,這個上下文,在調用function的時候,提供一些簡單的方式來創建自由變量或私有子function。

eg:

// 由於該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內部)。

正文核心
1、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/18209252090847232  
new 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(); } ());

希望這里的一些例子,可以讓大家明白,什么叫自執行,什么叫立即調用。

注意:arguments.callee在ECMAScript 5 strict mode里被廢棄了,所以在這個模式下,其實是不能用的。

在JS中最簡單的調用方式,直接寫到html的body標簽里面:
 
 
 
         
< body  onload = "myfunction()" >
< html > < body  onload = "func1();func2();func3();" > </ body > </ html >
在JS中調用方式: 
  <script type= "text/javascript" >
    function  myfun()  

{    alert("this window.onload");   }   /*用window.onload調用myfun()*/

    window.onload = myfun; //不要括號
 </script>  
 <script type= "text/javascript" >
    window.onload= function (){
      func1();
      func2();
     func3(); }
 </script>

2、JQ方法  

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特效 });

3)還有一種簡寫方式 $(function() { $("table tr:nth-child(even)").addClass("even"); //任何需要執行的js特效 });

參考: http://www.jb51.net/article/81724.htm
http://blog.csdn.net/limlimlim/article/details/9198111

http://www.cnblogs.com/ayning/p/4113314.html 









免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM