Effective JavaScript Item 13 使用即時調用的函數運算式(IIFE)來建立局部域

來源:互聯網
上載者:User

Effective JavaScript Item 13 使用即時調用的函數運算式(IIFE)來建立局部域

本系列作為Effective JavaScript的讀書筆記。

所謂的即時調用的函數運算式,這個翻譯也許不太準確,它對應的英文原文是Immediately Invoked Function Expression (IIFE)。下文也使用IIFE來表達這一概念。

首先看一個程式:


function wrapElements(a) {var result = [], i, n;for (i = 0, n = a.length; i < n; i++) {result[i] = function() { return a[i]; };}return result;}var wrapped = wrapElements([10, 20, 30, 40, 50]);var f = wrapped[0];f(); // ?

這個程式的作用是,將傳入到wrapElements中的數組的每個元素進行一次"打包"操作,將元素替換成一個返回它們自身的函數,

也許你會認為最後輸出的而結果是10,但是最後的結果實際上是undefined。

會做出這種符合直覺的假設的原因是,在function() { return a[i]; };這段代碼中,一般會認為這裡的i就是當前迴圈時使用到的變數i,那麼下面的賦值就應該成立:


result[1] = function() { return a[1]; };

但是,不要忘了一個重要的事實,在以上的賦值語句中,首先會建立一個閉包。在這個閉包中引用到了其外部的變數i,回顧在Item 11我們學習到的關於閉包的一個原則,就是閉包會以引用的形式儲存其外部的變數,而不是以值的形式。

所以,在迴圈結束之後,i的值應該是5。那麼在調用wrapped[0]()時,就相當於調用:return a[5]。很顯然,這個值是不存在的,故返回undefined。

如果將上述代碼換成下面這樣:


function wrapElements(a) {var result = [];for (var i = 0, n = a.length; i < n; i++) {result[i] = function() { return a[i]; };}return result;}var wrapped = wrapElements([10, 20, 30, 40, 50]);var f = wrapped[0];f(); // ?

可以發現,變數i和n直到for迴圈開始的時候才會開始。那麼結果是怎麼樣的呢?

結果還是undefined。

這是因為VariableHoisting(Item 12)的緣故。無論在一個function中的哪裡聲明變數,該變數的定義部分總會出現在function的開始處。

那麼,如何讓程式以我們期待的方式運行呢,IIFE就派上用場了:


function wrapElements(a) {var result = [];for (var i = 0, n = a.length; i < n; i++) {(function() {var j = i;result[i] = function() { return a[j]; };})();}return result;}

在for迴圈中,建立了一個IIFE,將當前的迴圈變數i賦值給了j,然後在後面的function中返回的是a[j]。這相當使用了另外一個局部變數將外部變數當前的值給記錄下來,以便將來使用。那麼IIFE的價值就在於它能夠克服JavaScript語言中沒有塊範圍(Block Scoping)的弊端:通過建立一個匿名的閉包,將某個外部變數的當前值給儲存起來。就好比將一個變數的當前值"凍結"住,供將來使用。

IIFE的另一種形式是將需要"凍結"的變數作為參數傳入到IIFE中:


function wrapElements(a) {var result = [];for (var i = 0, n = a.length; i < n; i++) {(function(j) {result[i] = function() { return a[j]; };})(i);}return result;}

在使用IIFE的時候,有兩個注意事項:

  1. 如果在for或者while迴圈中使用了IIFE,那麼注意不要在IIFE中包含break以及continue語句。因為break和continue只有在迴圈中才能夠使用,否則拋出SyntaxError: Illegal break statement。
  2. 如果IIFE中使用了this或者arguments,那麼它們的意義可能會和你想象的有出入,關於這一點,在後續的Items中會進行介紹。

    總結:

    1. 閉包會儲存外部變數的引用,而不是值
    2. 使用IIFE來建立局部範圍

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.