JavaScript閉包

一、閉包有什么用

1、能夠在函數(shù)外部引用函數(shù)內(nèi)部的變量(變量作用域);

2、讓變量的值始終保持在內(nèi)存中(垃圾回收機制),避免全局變量的污染;

3、私有成員的存在。

二、為什么要引入閉包

? ? ? 在第一點說明了使用閉包的好處,備注里說明了使用閉包的原因。正是為了解決JavaScript變量作用域和垃圾回收機制所帶來的問題耳引出的閉包。

1、變量作用域:

在JavaScript中,沒有塊級左右域,只有全局作用域和局部作用域,如下:

例1:? 函數(shù)內(nèi)部可以直接讀取全局變量

var n=999;

function f1(){

? ? ? ?alert(n);

}

f1(); ?// 999

例2:? 函數(shù)外部無法讀取函數(shù)內(nèi)的局部變量

function f1(){

? ? ? var n=999;

}

alert(n);// error

例3:函數(shù)內(nèi)聲明變量,沒有使用var,相當(dāng)于定義了全局變量

function f1(){

? ? ? ?n=999;

}

f1();

alert(n);// 999



2、JS垃圾回收機制

? ? ? JavaScript中,會按照固定的時間回收不再使用的變量,以釋放其所占用的內(nèi)存。通過閉包能夠避免變量被回收。


三、如何使用閉包

1、在函數(shù)外部獲取內(nèi)部變量

例4:function f1(){

? ? ? ? ? ? n=999;

? ? ? ? ? ?function f2(){

? ? ? ? ? ?alert(n);// 999

? ? ?}

}

既然f2能夠訪問f1 中的所有變量,所以將f2作為返回值,便可 在f1外訪問f1內(nèi)的變量了,如例5:

例5:function f1(){

? ? ? ? ? ?n=999;

? ? ? ? ? ?function f2(){

? ? ? ? ? ? ? ? ? ?alert(n);

? ? ? ? ? ?}

? ? ? ? ?return f2;

}

var result=f1();

result();// 999


2、將變量保存在內(nèi)存中,例6.

例6:

function f1(){

? ? ? ? ?var n=999;

? ? ? ? ?nAdd=function(){

? ? ? ? ? ? ? ? n+=1

? ? ? ? ? }

? ? ? ? ? function f2(){

? ? ? ? ? ? ? ? ? ?alert(n);

? ? ? ? ? ?}

? ? ? ? ? return f2;

}

var result=f1();

result();// 999

nAdd();

result();// 1000

? ? ? ?結(jié)果顯示,它一共運行了兩次,第一次的值是999,第二次的值是1000。這證明了,函數(shù)f1中的局部變量n一直保存在內(nèi)存中,并沒有在f1調(diào)用后被自動清除。

? ? ? ? 這是因為f1 和 f2 ?相互引用,f1是f2的父函數(shù),而f2被賦給了一個全局變量,這導(dǎo)致f2始終在內(nèi)存中,而f2的存在依賴于f1,因此f1也始終在內(nèi)存中,不會在調(diào)用結(jié)束后,被垃圾回收機制(garbage collection)回收。


四、閉包例子

例7:

vari =5;

function a() {

? ? ? ?var i =0;

? ? ? ?function b() {

? ? ? ? ? ? ? alert(i++);

? ? ? ? }

? ? ? ?return b;

}

a()(); ? //0

例8:

var name ='The Window';

var object1 = {

? ? ? ?name:'My Object',

? ? ? ?getNameFunc:function() {

? ? ? ? ? ? ? ? return function() {

? ? ? ? ? ? ? ? ? ? ? ?return this.name;

? ? ? ? ? ? ? ?};

? ? ? ? }

};

alert(object1.getNameFunc()()); ? //The Window

? ? ? 解釋一下例8.? object1.getNameFunc() 的結(jié)果是第一個return 的內(nèi)容,object1.getNameFunc()() 實際上就相當(dāng)于在全局環(huán)境下執(zhí)行了第一個return 的內(nèi)容,所以this ?指向的是window, 所以this.name = window.name = 'The Window'. ?


例9:

a、 ??

var data = [];

for (var i = 0; i < 3; i++) {

? ? ? ? ? ? console.log('i:'+i);

? ? ? ? ? ? data[i] = function () {

? ? ? ? ? ? ? ? ? ? ?console.log(i)

? ? ? ? ? ? ? }

}

data[0](); ?//3

data[1](); ?//3

data[2](); ?//3


b、

var data = [];

for(vari =0;i <3;i ++){

? ? ? ? console.log('i:'+i);

? ? ? ? data[i] = (function(i) {

? ? ? ? ? ? ? ? ? return function() {

? ? ? ? ? ? ? ? ? ? ? ? ? console.log(i);

? ? ? ? ? ? ? ? }

? ? ? ? })(i)

}

data[0](); ? ?//0

data[1](); ? ?//1

data[2](); ? //2

五、使用閉包的注意點

1、由于閉包會使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會造成網(wǎng)頁的性能問題,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。

注:順便提一下內(nèi)存泄漏和內(nèi)存溢出的區(qū)別。

內(nèi)存泄露:memory leak,指程序申請了內(nèi)存但不歸還,導(dǎo)致這些內(nèi)存無法再配分配自己也無法使用。

內(nèi)存溢出:out of memory,指內(nèi)存不夠用了。假如你定義了一個Interger,卻給了一個 Long 的值,便會內(nèi)存溢出。

在用戶使用中,少量的內(nèi)存泄露感覺不出,但內(nèi)存泄露堆積后果很嚴(yán)重,將導(dǎo)致內(nèi)存溢出。

2、閉包會在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值。所以,如果你把父函數(shù)當(dāng)作對象(object)使用,把閉包當(dāng)作它的公用方法(Public Method),把內(nèi)部變量當(dāng)作它的私有屬性(private value),這時一定要小心,不要隨便。

舉個例子:

function aaa() {?

? ? ? ?var c =1;

? ? ? ? return function() {

? ? ? ? ? ? ? alert(c++);

? ? ? ? ?};

}

var ? fun =aaa();

fun();//1

fun();//2

fun =null;//回收

var ?fun =aaa();

fun();//1


function aaa() {

? ? ? ? ?var c =1;

? ? ? ? ?return ?function() {

? ? ? ? ? ? ? ? ? ?alert(c++);

? ? ? ? ? };

}

aaa()();//1

aaa()();//1

var? fun =aaa();

fun();//1




此篇文章參考自:(http://www.jb51.net/article/24101.htm)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容