用最通俗易懂的代碼幫助新手理解javascript閉包 推薦
今天就結(jié)合這兩本書(shū),用最淺顯的語(yǔ)言和最通俗的方式談?wù)刯avascript中的閉包,因?yàn)橐彩切率?,所以有有誤的地方請(qǐng)各位指出,謝謝
一. 準(zhǔn)備知識(shí)
1.函數(shù)作為函數(shù)的參數(shù)
在學(xué)習(xí)javascript中,你始終要有一個(gè)有學(xué)習(xí)與其他語(yǔ)言不同的概念:函數(shù)(function)不么特殊的東西,它也是一種數(shù)據(jù),與bool ,string,number沒(méi)有什么兩樣。
函數(shù)的參數(shù)可以string,number,bool如:
function(a, b) {return a + b;}
但同樣也可以傳入函數(shù)。對(duì)你沒(méi)有聽(tīng)錯(cuò),函數(shù)的參數(shù)是函數(shù)!加入你有以下兩個(gè)函數(shù):
//把三個(gè)數(shù)翻一倍
function multiplyByTwo(a, b, c) {
var i, ar = [];
for(i = 0; i < 3; i++) {
ar[i] = arguments[i] * 2;
}
return ar;
}
//把數(shù)加一
function addOne(a) {
return a + 1;
}
然后這么使用
var myarr = [];
//先把每個(gè)數(shù)乘以二,用了一個(gè)循環(huán)
myarr = multiplyByTwo(10, 20, 30);
//再把每個(gè)數(shù)加一,又用了一個(gè)循環(huán)
for (var i = 0; i < 3; i++) {myarr[i] = addOne(myarr[i]);}
要注意到其實(shí)這個(gè)過(guò)程用了兩個(gè)循環(huán),還是有提升的空間的,不如這么做:
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ù)傳遞進(jìn)去了,并且在第一個(gè)循環(huán)中直接調(diào)用。這樣的函數(shù)就是著名的回調(diào)函數(shù)(Callback function)
2.函數(shù)作為返回值
在函數(shù)中可以有返回值,但是我們一般都熟悉數(shù)值的返回,如
function ex(){
return 12
}
但你一旦意識(shí)到函數(shù)只是一種數(shù)據(jù)的話,你就可以想到同樣可以返回函數(shù)。注意看下面這個(gè)函數(shù):
function a() {
alert('A!');
return function(){
alert('B!');
};
}
它返回了一個(gè)彈出”B!”的函數(shù)。接下來(lái)使用它:
var newFunc = a();
newFunc();
結(jié)果是什么呢?首先執(zhí)行a()的時(shí)候,彈出”A!”,此時(shí)newFunc接受了a的返回值,一個(gè)函數(shù)——此時(shí)newFunc就變成了那個(gè)被a返回的函數(shù),再執(zhí)行newFunc時(shí),彈出”B!”
3.javascript的作用域
javascript的作用域很特別,它是以函數(shù)為單位的,而不是像其他語(yǔ)言以塊為單位(如一個(gè)循環(huán)中),看下面這個(gè)例子:
var a = 1; function f(){var b = 1; return a;}
如果你此時(shí)試圖想得到b的值:在firebug中試圖輸入alert(b)的話,你會(huì)得到錯(cuò)誤提示:
b is not defined
為什么你可以這么理解:你所在的編程環(huán)境或者窗口是最頂級(jí)的一個(gè)函數(shù),好像一個(gè)宇宙,但是b只是在你內(nèi)部函數(shù)的一個(gè)變量,宇宙中的小星球上的一個(gè)點(diǎn),你很難找到它,所以在這個(gè)環(huán)境中你不能調(diào)用它的;反之這個(gè)內(nèi)部函數(shù)可以調(diào)用變量a,因?yàn)樗┞对谡麄€(gè)宇宙中,無(wú)處藏身,同時(shí)也可以調(diào)用b,因?yàn)樗驮谧约旱男乔蛏?,函?shù)內(nèi)部。
就上面這個(gè)例子說(shuō):
在f()外,a可見(jiàn),b不可見(jiàn)
在f()內(nèi),a可見(jiàn),b也可見(jiàn)
再?gòu)?fù)雜點(diǎn):
var a = 1; //b,c在這一層都不可見(jiàn)
function f(){
var b = 1;
function n() { //a,b,c對(duì)這個(gè)n函數(shù)都可以調(diào)用,因?yàn)閍,b暴露在外,c又是自己內(nèi)部的
var c = 3;
}
}
問(wèn)你,函數(shù)b可以調(diào)用變量c嗎?不行,記住javascript的作用域是以函數(shù)為單位的,c在n的內(nèi)部,所以對(duì)f來(lái)說(shuō)是不可見(jiàn)的。
開(kāi)始正式談閉包:
首先看這個(gè)圖:
假設(shè)G,F,N 分別代表三個(gè)層次的函數(shù),層次如圖所示,a,b,c分別是其中的變量。根據(jù)上面談到的作用域,我們有如下結(jié)論:
- 如果你在a點(diǎn),你是不可以引用b的,因?yàn)閎對(duì)你是不可見(jiàn)的
- 只有c可以引用b
閉包的吊詭之處的就在于發(fā)生了如下情況:
N突破了F的限制!跑到于a同一層了!因?yàn)楹瘮?shù)只認(rèn)它們?cè)诙x時(shí)所處的環(huán)境(而不是執(zhí)行時(shí),這點(diǎn)很重要),N中的c仍然可以訪問(wèn)b!此時(shí)的a還是不可以訪問(wèn)b!
但是這是怎么實(shí)現(xiàn)的呢?如下:
閉包1:
function f(){
var b = "b";
return function(){ //沒(méi)有名字的函數(shù),所以是匿名函數(shù)
return b;
}
}
注意返回的函數(shù)可以訪問(wèn)它父親函數(shù)中的變量b
此時(shí)如果你想取b的值,當(dāng)然是undefined
但是如果你這么做:
var n = f();
n();
你可以取到b的值了!雖然此時(shí)n函數(shù)在f的外面,b又屬于f內(nèi)部的變量,但是f內(nèi)部出了一個(gè)內(nèi)鬼,返回了b的值……
現(xiàn)在大家有點(diǎn)感覺(jué)了吧
閉包2:
var n;
function f(){
var b = "b";
n = function(){
return b;
}
}
如果此時(shí)調(diào)用f會(huì)怎么樣?那就生成了一個(gè)n的全局范圍函數(shù),但是它卻能訪問(wèn)f的內(nèi)部,照樣返回b的值,與上面有異曲同工之妙!
閉包3:
你還可以用閉包訪問(wèn)函數(shù)的參數(shù)
function f(arg) {
var n = function(){
return arg;
};
arg++;
return n;
}
此時(shí)如果使用:
var m = f(123);
m();
結(jié)果是124
因?yàn)榇藭r(shí)f中返回的匿名函數(shù)經(jīng)過(guò)了兩道轉(zhuǎn)手,先給n,再賦給外面的m,但本質(zhì)沒(méi)有變,把定義時(shí)父函數(shù)的參數(shù)返回了
閉包4:
var getValue, setValue;
function() {
var secret = 0;
getValue = function(){
return secret;
};
setValue = function(v){
secret = v;
};
})
運(yùn)行:
getValue()
0
setValue(123)
getValue()
123
這個(gè)就不用解釋了吧,如果你有面向?qū)ο笳Z(yǔ)言基礎(chǔ)的話(如C#),這里的getValue和setValue就類(lèi)似于一個(gè)對(duì)象的屬性訪問(wèn)器,你可以通過(guò)這兩個(gè)訪問(wèn)器來(lái)賦值和取值,而不是能訪問(wèn)其中內(nèi)容
其實(shí)書(shū)中還有幾個(gè)閉包的例子,但是原理用上面四個(gè)就足夠了,希望能起拋磚引玉的作用,給javascript進(jìn)階者對(duì)閉包有一個(gè)更深刻的理解
- javascript閉包的高級(jí)使用方法實(shí)例
- JavaScript自執(zhí)行閉包的小例子
- 深入Javascript函數(shù)、遞歸與閉包(執(zhí)行環(huán)境、變量對(duì)象與作用域鏈)使用詳解
- 談?wù)凧avaScript中的函數(shù)與閉包
- 深入理解JavaScript 閉包究竟是什么
- JavaScript中的作用域鏈和閉包
- javascript學(xué)習(xí)筆記(十三) js閉包介紹(轉(zhuǎn))
- Javascript 閉包引起的IE內(nèi)存泄露分析
- 深入理解JavaScript系列(16) 閉包(Closures)
- JavaScript 高級(jí)篇之閉包、模擬類(lèi),繼承(五)
- JavaScript高級(jí)程序設(shè)計(jì) 讀書(shū)筆記之八 Function類(lèi)及閉包
- javaScript 利用閉包模擬對(duì)象的私有屬性
- JavaScript閉包 懂不懂由你反正我是懂了
- JavaScript 匿名函數(shù)(anonymous function)與閉包(closure)
- javascript的閉包介紹(司徒正美)
- javascript 閉包
- Javascript閉包演示代碼小結(jié)
- 基于javascript 閉包基礎(chǔ)分享
相關(guān)文章
鼠標(biāo)焦點(diǎn)離開(kāi)文本框時(shí)驗(yàn)證的js代碼
本文為大家介紹下利用js來(lái)驗(yàn)證文本框的值,當(dāng)鼠標(biāo)焦點(diǎn)離開(kāi)文本框時(shí)進(jìn)行驗(yàn)證,示例代碼如下,感興趣的朋友可以參考下哈,希望對(duì)大家有所幫助2013-07-07javascript json字符串到j(luò)son對(duì)象轉(zhuǎn)義問(wèn)題
今天小編就為大家分享一篇關(guān)于javascript json字符串到j(luò)son對(duì)象轉(zhuǎn)義問(wèn)題,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01微信小程序wx.request實(shí)現(xiàn)后臺(tái)數(shù)據(jù)交互功能分析
這篇文章主要介紹了微信小程序wx.request實(shí)現(xiàn)后臺(tái)數(shù)據(jù)交互功能,分析微信小程序wx.request在后臺(tái)數(shù)據(jù)交互過(guò)程中遇到的問(wèn)題與相關(guān)的解決方法,需要的朋友可以參考下2017-11-11微信小程序?qū)崿F(xiàn)簡(jiǎn)單手寫(xiě)簽名組件的方法實(shí)例
在使用微信的時(shí)候,為方便我們發(fā)送文件可以直接在上面進(jìn)行手寫(xiě)簽名,這篇文章主要給大家介紹了關(guān)于利用微信小程序?qū)崿F(xiàn)簡(jiǎn)單手寫(xiě)簽名組件的相關(guān)資料,需要的朋友可以參考下2021-07-07uni-app使用uploadFile上傳多張圖片的具體實(shí)現(xiàn)
在微信小程序中不支持多張圖片上傳,需要做循環(huán)實(shí)現(xiàn)多張圖片上傳,下面這篇文章主要給大家介紹了關(guān)于uni-app使用uploadFile上傳多張圖片的具體實(shí)現(xiàn),需要的朋友可以參考下2023-04-04JavaScript 無(wú)縫上下左右滾動(dòng)加定高定寬停頓效果(兼容ie/ff)
JavaScript 指定寬度高度的無(wú)間斷滾動(dòng)實(shí)現(xiàn)代碼,這樣的效果適合作為焦點(diǎn)新聞的輪播顯示。2010-03-03實(shí)現(xiàn)web打印的各種方法介紹及實(shí)現(xiàn)代碼
web的打印方法具我自己懂得知道的有:JQuery插件Jqprint實(shí)現(xiàn);JQery打印插件PrintArea實(shí)現(xiàn)網(wǎng)頁(yè)打印;CSS控制網(wǎng)頁(yè)打印樣式,本文詳細(xì)介紹實(shí)現(xiàn)步驟,感興趣的朋友可以了解下2013-01-01JS多物體實(shí)現(xiàn)緩沖運(yùn)動(dòng)效果示例
這篇文章主要介紹了JS多物體實(shí)現(xiàn)緩沖運(yùn)動(dòng)效果的方法,涉及javascript基于時(shí)間函數(shù)進(jìn)行動(dòng)態(tài)運(yùn)算實(shí)現(xiàn)頁(yè)面元素動(dòng)態(tài)操作的相關(guān)技巧,需要的朋友可以參考下2016-12-12JavaScript中通用的jquery動(dòng)畫(huà)滾屏實(shí)例
這篇文章主要介紹了JavaScript中通用的jquery動(dòng)畫(huà)滾屏實(shí)例,本文通過(guò)實(shí)際代碼來(lái)詳解實(shí)現(xiàn)方法,需要的朋友可以參考一下2022-07-07