亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

用最通俗易懂的代碼幫助新手理解javascript閉包 推薦

 更新時間:2012年03月01日 22:44:50   作者:  
我同樣也是個javascript新手,怎么說呢,先學(xué)的jquery,精通之后發(fā)現(xiàn)了javascript的重要性,再回過頭來學(xué)javascript面向?qū)ο缶幊?/div>
最近看了幾篇有關(guān)javascript閉包的文章,包括最近正火的湯姆大叔系列,還有《javascript高級程序設(shè)計》中的文章,……我看不懂,里面有些代碼是在大學(xué)教科書中看都沒看過的,天書一般。幸好最近遇到兩本好書《ppk on javascript》和《object-oriented JavaScript》,正字閱讀中,后者還沒有中文版,但前者還是建議看原版,寫的不復(fù)雜,有興趣的朋友可以看看,適合想進階的朋友。
今天就結(jié)合這兩本書,用最淺顯的語言和最通俗的方式談?wù)刯avascript中的閉包,因為也是新手,所以有有誤的地方請各位指出,謝謝
一. 準備知識
1.函數(shù)作為函數(shù)的參數(shù)
在學(xué)習(xí)javascript中,你始終要有一個有學(xué)習(xí)與其他語言不同的概念:函數(shù)(function)不么特殊的東西,它也是一種數(shù)據(jù),與bool ,string,number沒有什么兩樣。
函數(shù)的參數(shù)可以string,number,bool如:
function(a, b) {return a + b;}
但同樣也可以傳入函數(shù)。對你沒有聽錯,函數(shù)的參數(shù)是函數(shù)!加入你有以下兩個函數(shù):
復(fù)制代碼 代碼如下:

//把三個數(shù)翻一倍
function multiplyByTwo(a, b, c) {
var i, ar = [];
for(i = 0; i < 3; i++) {
ar[i] = arguments[i] * 2;
}
return ar;
}

復(fù)制代碼 代碼如下:

//把數(shù)加一
function addOne(a) {
return a + 1;
}

然后這么使用
復(fù)制代碼 代碼如下:

var myarr = [];
//先把每個數(shù)乘以二,用了一個循環(huán)
myarr = multiplyByTwo(10, 20, 30);
//再把每個數(shù)加一,又用了一個循環(huán)
for (var i = 0; i < 3; i++) {myarr[i] = addOne(myarr[i]);}

要注意到其實這個過程用了兩個循環(huán),還是有提升的空間的,不如這么做:
復(fù)制代碼 代碼如下:

function multiplyByTwo(a, b, c, addOne) {
var i, ar = [];
for(i = 0; i < 3; i++) {
ar[i] = addOne (arguments[i] * 2);
}
return ar;
}

這樣就把函數(shù)當(dāng)做參數(shù)傳遞進去了,并且在第一個循環(huán)中直接調(diào)用。這樣的函數(shù)就是著名的回調(diào)函數(shù)(Callback function)
2.函數(shù)作為返回值
在函數(shù)中可以有返回值,但是我們一般都熟悉數(shù)值的返回,如
復(fù)制代碼 代碼如下:

function ex(){
return 12
}

但你一旦意識到函數(shù)只是一種數(shù)據(jù)的話,你就可以想到同樣可以返回函數(shù)。注意看下面這個函數(shù):
復(fù)制代碼 代碼如下:

function a() {
alert('A!');
return function(){
alert('B!');
};
}

它返回了一個彈出”B!”的函數(shù)。接下來使用它:
復(fù)制代碼 代碼如下:

var newFunc = a();
newFunc();

結(jié)果是什么呢?首先執(zhí)行a()的時候,彈出”A!”,此時newFunc接受了a的返回值,一個函數(shù)——此時newFunc就變成了那個被a返回的函數(shù),再執(zhí)行newFunc時,彈出”B!”
3.javascript的作用域
javascript的作用域很特別,它是以函數(shù)為單位的,而不是像其他語言以塊為單位(如一個循環(huán)中),看下面這個例子:
var a = 1; function f(){var b = 1; return a;}
如果你此時試圖想得到b的值:在firebug中試圖輸入alert(b)的話,你會得到錯誤提示:
b is not defined
為什么你可以這么理解:你所在的編程環(huán)境或者窗口是最頂級的一個函數(shù),好像一個宇宙,但是b只是在你內(nèi)部函數(shù)的一個變量,宇宙中的小星球上的一個點,你很難找到它,所以在這個環(huán)境中你不能調(diào)用它的;反之這個內(nèi)部函數(shù)可以調(diào)用變量a,因為它暴露在整個宇宙中,無處藏身,同時也可以調(diào)用b,因為它就在自己的星球上,函數(shù)內(nèi)部。
就上面這個例子說:
在f()外,a可見,b不可見
在f()內(nèi),a可見,b也可見
再復(fù)雜點:
復(fù)制代碼 代碼如下:

var a = 1; //b,c在這一層都不可見
function f(){
var b = 1;
function n() { //a,b,c對這個n函數(shù)都可以調(diào)用,因為a,b暴露在外,c又是自己內(nèi)部的
var c = 3;
}
}

問你,函數(shù)b可以調(diào)用變量c嗎?不行,記住javascript的作用域是以函數(shù)為單位的,c在n的內(nèi)部,所以對f來說是不可見的。

開始正式談閉包:

首先看這個圖:

 

假設(shè)G,F,N 分別代表三個層次的函數(shù),層次如圖所示,a,b,c分別是其中的變量。根據(jù)上面談到的作用域,我們有如下結(jié)論:

  1. 如果你在a點,你是不可以引用b的,因為b對你是不可見的
  2. 只有c可以引用b

閉包的吊詭之處的就在于發(fā)生了如下情況:

 

N突破了F的限制!跑到于a同一層了!因為函數(shù)只認它們在定義時所處的環(huán)境而不是執(zhí)行時,這點很重要),N中的c仍然可以訪問b!此時的a還是不可以訪問b!

但是這是怎么實現(xiàn)的呢?如下:
閉包1:

復(fù)制代碼 代碼如下:

function f(){
var b = "b";
return function(){ //沒有名字的函數(shù),所以是匿名函數(shù)
return b;
}
}

注意返回的函數(shù)可以訪問它父親函數(shù)中的變量b
此時如果你想取b的值,當(dāng)然是undefined
但是如果你這么做:
復(fù)制代碼 代碼如下:

var n = f();
n();

你可以取到b的值了!雖然此時n函數(shù)在f的外面,b又屬于f內(nèi)部的變量,但是f內(nèi)部出了一個內(nèi)鬼,返回了b的值……
現(xiàn)在大家有點感覺了吧
閉包2:
復(fù)制代碼 代碼如下:

var n;
function f(){
var b = "b";
n = function(){
return b;
}
}

如果此時調(diào)用f會怎么樣?那就生成了一個n的全局范圍函數(shù),但是它卻能訪問f的內(nèi)部,照樣返回b的值,與上面有異曲同工之妙!
閉包3:
你還可以用閉包訪問函數(shù)的參數(shù)
復(fù)制代碼 代碼如下:

function f(arg) {
var n = function(){
return arg;
};
arg++;
return n;
}

此時如果使用:
復(fù)制代碼 代碼如下:

var m = f(123);
m();

結(jié)果是124
因為此時f中返回的匿名函數(shù)經(jīng)過了兩道轉(zhuǎn)手,先給n,再賦給外面的m,但本質(zhì)沒有變,把定義時父函數(shù)的參數(shù)返回了
閉包4:
復(fù)制代碼 代碼如下:

var getValue, setValue;
function() {
var secret = 0;
getValue = function(){
return secret;
};
setValue = function(v){
secret = v;
};
})

運行:
復(fù)制代碼 代碼如下:

getValue()
0
setValue(123)
getValue()
123

這個就不用解釋了吧,如果你有面向?qū)ο笳Z言基礎(chǔ)的話(如C#),這里的getValue和setValue就類似于一個對象的屬性訪問器,你可以通過這兩個訪問器來賦值和取值,而不是能訪問其中內(nèi)容
其實書中還有幾個閉包的例子,但是原理用上面四個就足夠了,希望能起拋磚引玉的作用,給javascript進階者對閉包有一個更深刻的理解

相關(guān)文章

最新評論