深入理解js立即執行函數

看過jQuery源碼的人應該知道,jQuery開篇用的就是立即執行函數。立即執行函數常用於第三方庫,好處在於隔離作用域,任何一個第三方庫都會存在大量的變量和函數,爲了避免變量污染(命名衝突),開發者們想到的解決辦法就是使用立即執行函數。

1.什麼是立即執行函數(IIFE)

在瞭解立即執行函數之前先明確一下函數聲明、函數表達式及匿名函數的形式,如下圖:

接下來看立即執行函數的兩種常見形式:( function(){…} )()和( function (){…} () ),一個是一個匿名函數包裹在一個括號運算符中,後面再跟一個小括號,另一個是一個匿名函數後面跟一個小括號,然後整個包裹在一個括號運算符中,這兩種寫法是等價的。要想立即執行函數能做到立即執行,要注意兩點,一是函數體後面要有小括號(),二是函數體必須是函數表達式而不能是函數聲明。先看下圖:

從圖中可以看出,除了使用()運算符之外,!,+,-,=等運算符都能起到立即執行的作用。這些運算符的作用就是將匿名函數或函數聲明轉換爲函數表達式,如下圖所示,函數體是函數聲明的形式,使用運算符將其轉換爲函數表達式之後就可達到立即執行效果:

2.使用立即執行函數的好處

通過定義一個匿名函數,創建了一個新的函數作用域,相當於創建了一個“私有”的命名空間,該命名空間的變量和方法,不會破壞污染全局的命名空間。此時若是想訪問全局對象,將全局對象以參數形式傳進去即可,如jQuery代碼結構:

其中window即是全局對象。給其傳入參數這樣的好處是,可以縮短查詢時的作用域鏈。作用域隔離非常重要,是一個JS框架必須支持的功能,jQuery被應用在成千上萬的JavaScript程序中,必須確保jQuery創建的變量不能和導入他的程序所使用的變量發生衝突。

 

閉包和立即執行函數

  看個例子:

var car = {
    speed:0,
    start:function(){ this.speed=40; },
    getspeed:function(){ return this.speed; }
};
car.start();
console.log(car.getspeed()); //print 40

  這個對象有其成員變量“speed”及成員函數“start”和“getspeed”,但是它的成員變量沒有私有化,同時它也沒有辦法被繼承。要實現對象的繼承,你可以使用構造函數和原型繼承。但怎麼才能將成員變量私有化來實現對象的封裝呢(而且有時候我們也不想那麼麻煩使用原型)?有心的讀者看了上面閉包的介紹,肯定馬上有想法了。對,使用閉包!

function car() {
    var speed = 0;
    return { //返回的是一個對象
        start:function() {
            speed = 50;
        },
        getspeed:function () {
         return speed;
        }
    }
}

var car1 = car();
car1.start();
console.log(car1.getspeed()); //print 50

  說了那麼多,跟立即執行函數有什麼關係呢。你再仔細看看上面的例子,你有了閉包函數來幫你創建“car”對象,這個函數就類似於工廠方法,它可以根據你的需要創建多個不同的對象。

  不過開發的時候經常遇到這樣的情況,就是我們希望對象只有一份,比如jQuery庫的對象,它必須確保整個程序只有一份,多了也沒有。在後端開發模式中,這叫單例模式,可以通過私有化構造函數來實現,那麼在js裏呢?

  既然函數沒法私有化,那麼唯一的辦法就是讓這個工廠方法能且只能被調用一次。不能多次調用,那這個函數一定要是匿名函數;而且能被調用一次,那就必須在聲明的時候立馬執行。這時候,我們就可以邀請立即執行函數出場了:

var car = (function () {
    var speed = 0;
    return {
        start:function () {
           speed=60;
        },
        getspeed:function () {
           return speed;
        }
    }
})();

car.start();
console.log(car.getspeed()); //print 60  

  很多人一開始會看錯,認爲對象“car”是一個函數,其實它是這個匿名的工廠方法執行完返回的對象,該對象擁有“start”和“getspeed”兩個成員函數,而這兩個函數所需要訪問的“speed”變量對外不可見。同時你無法再次調用這個匿名的工廠方法來創建一個相同的對象。是不是很神奇?一個單例的,有着私有成員的對象就這麼建好了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章