javascript閉包和立即執行函數的作用


一、閉包——closure

  先看一個閉包的例子。我們想實現一個計數器,最簡單的方法就是定義一個全局變量,計數的時候將其加1。但是全局變量有風險,哪里都有可能不小心改掉它。那局部變量呢,

它只在函數內部有效,函數調用完后它就沒了,而且全局沒法使用。那我們用想讓計數器全局使用,又不想讓這個變量被隨便修改怎么辦。這就需要閉包了:

function count(){
    var i=0;
    return function () {
        return ++i;
    }
}    

  這個例子實現了一個簡單的計數器。函數"count()"定義了一個局部變量“i”,並返回一個內部匿名函數。因為是內部函數,所以它可以訪問其外部函數的局部變量“i”,並且將其加1並返回。讓我們看下怎么使用這個計數器。

c1 = count();
console.log(c1());  //print1
console.log(c1());  //print2
console.log(c1());  //print3

c2 = count();
console.log(c2());  //print1

 每次調用“count()”函數后就會生成一個計數器,而且不同的計數器之間不干擾。因為兩次調用同一個函數,創建的棧是不同的,因此棧內的局部變量是不同的。上例中,我們生成了全局計數器“c1”和“c2”,他們都是不帶參數的函數,即“count()”中返回的匿名函數。此后每次調用計數器,比如“c1()”,計數器就會自增1並返回。但是由於“count()”函數已經調用完畢,我們將無法通過任何其他辦法去修改“count()”中變量“i”的值。這就是閉包最實用的功能,就是將你想操作的變量或對象隱藏起來,只允許特定的方法才能訪問它

二、立即執行函數

  n年前看到jQuery的源碼時,很好奇它的最外層結構是這樣的(現在已經不一樣了):var jQuery = (function(){……})();

  作為前端小白的我,實在想不通這是為什么,好好定義一個函數,為啥還要調用它。大家知道javascript在es6之前並不嚴格支持面向對象。js的對象其實就是一個map,比如下面的例子:

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”變量對外不可見。同時你無法再次調用這個匿名的工廠方法來創建一個相同的對象。是不是很神奇?一個單例的,有着私有成員的對象就這么建好了。

  立即執行函數還有一種寫法就是:

var car = (function () {
	……				
}());

  

本篇文章的出處:http://www.bjhee.com/js-closure-iif.html 


免責聲明!

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



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