立即執行函數的定義及使用場景——循環中有異步,下標值始終為最后一位下標


一、什么是立即執行函數?

聲明一個函數,並馬上調用這個匿名函數就叫做立即執行函數;也可以說立即執行函數是一種語法,讓你的函數在定義以后立即執行;

立即執行函數的創建步驟,看下圖:

二、立即執行函數的寫法:

有時,我們定義函數之后,立即調用該函數,這時不能在函數的定義后面直接加圓括號,這會產生語法錯誤。產生語法錯誤的原因是,function 這個關鍵字,既可以當做語句,也可以當做表達式,比如下邊:

//語句
function fn() {}; //表達式
var fn = function (){};
為了避免解析上的歧義,JS引擎規定,如果function出現在行首,一律解析成語句。因此JS引擎看到行首是function關鍵字以后,認為這一段都是函數定義,不應該以原括號結尾,所以就報錯了。
解決方法就是不要讓function出現在行首,讓JS引擎將其理解為一個表達式,最簡單的處理就是將其放在一個圓括號里,比如下邊:
(function(){ //code
}()) (function (){ //code
})()
上邊的兩種寫法,都是以圓括號開頭,引擎會意味后面跟的是表達式,而不是一個函數定義語句,所以就避免了錯誤,這就叫做"立即調用的函數表達式"。
立即執行函數,還有一些其他的寫法(加一些小東西,不讓解析成語句就可以),比如下邊:
(function () {alert("我是匿名函數")}())   //用括號把整個表達式包起來
(function () {alert("我是匿名函數")})()  //用括號把函數包起來
!function () {alert("我是匿名函數")}()  //求反,我們不在意值是多少,只想通過語法檢查
+function () {alert("我是匿名函數")}() -function () {alert("我是匿名函數")}() ~function () {alert("我是匿名函數")}() void function () {alert("我是匿名函數")}() new function () {alert("我是匿名函數")}() 

三、立即執行函數的作用:

  • 不必為函數命名,避免了污染全局變量
  • 立即執行函數內部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量
  • 封裝變量
總而言之:立即執行函數會形成一個單獨的作用域,我們可以封裝一些臨時變量或者局部變量,避免污染全局變量

四、使用場景

1.怎樣使以下alert的結果為0,1,2:

<body>
    <ul id="list">
        <li>公司簡介</li>
        <li>聯系我們</li>
        <li>營銷網絡</li>
    </ul>
    <script>
       var list = document.getElementById("list"); var li = list.children; for(var i = 0 ;i<li.length;i++){ li[i].onclick=function(){ alert(i); // 結果總是3.而不是0,1,2
 } } </script>  
</body>
為什么alert總是3? 因為i是貫穿整個作用域的,而不是給每一個li分配一個i,點擊事件使異步,用戶一定是在for運行完了以后,才點擊,此時i已經變成3了。
那么怎么解決這個問題呢,可以用立即執行函數,給每個li創建一個獨立的作用域,在立即執行函數執行的時候,i的值從0到2,對應三個立即執行函數,這3個立即執行函數里邊的j分別是0,1,2所以就能正常輸出了,看下邊例子:
<body>
    <ul id="list">
        <li>公司簡介</li>
        <li>聯系我們</li>
        <li>營銷網絡</li>
    </ul>
    <script>
       var list = document.getElementById("list"); var li = list.children; for(var i = 0 ;i<li.length;i++){ ( function(j){ li[j].onclick = function(){ alert(j); })(i); //把實參i賦值給形參j } } </script>  
</body>

當然,也可以使用ES6的塊級作用域解決整個問題:

<body>
    <ul id="list">
        <li>公司簡介</li>
        <li>聯系我們</li>
        <li>營銷網絡</li>
    </ul>
    <script>
      var list = document.getElementById("list"); var li = list.children; for(let i = 0 ;i<li.length;i++){ li[i].onclick=function(){ alert(i); // 結果是0,1,2
 } } </script>  
</body>

2.如何避免了污染全局變量

某些代碼只需要執行一次,比如只需要顯示一個時間,但是這些代碼也需要一些臨時的變量,但是初始化過程結束之后,就再也不會被用到,如果將這些變量作為全局變量,不是一個好的主意,我們可以用立即執行函數——去將我們所有的代碼包裹在它的局部作用域中,不會讓任何變量泄露成全局變量,看如下代碼:

 

比如上面的代碼,如果沒有被包裹在立即執行函數中,而是直接以非函數的形式直接寫在<script>標簽里面,雖然也會立即執行,但是臨時變量todaydom,days,today,year,month,date,day,msg都將成為全局變量(初始化代碼遺留的產物)。
而用立即執行函數之后,這些變量都不會在全局變量中存在,以后也不會其他地方使用,有效的避免了污染全局變量。


免責聲明!

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



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