用最通俗易懂的代碼幫助新手理解javascript閉包 推薦
今天就結(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ù):
//把三個數(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 = [];
//先把每個數(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),還是有提升的空間的,不如這么做:
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ù)值的返回,如
function ex(){
return 12
}
但你一旦意識到函數(shù)只是一種數(shù)據(jù)的話,你就可以想到同樣可以返回函數(shù)。注意看下面這個函數(shù):
function a() {
alert('A!');
return function(){
alert('B!');
};
}
它返回了一個彈出”B!”的函數(shù)。接下來使用它:
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ù)雜點:
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é)論:
- 如果你在a點,你是不可以引用b的,因為b對你是不可見的
- 只有c可以引用b
閉包的吊詭之處的就在于發(fā)生了如下情況:
N突破了F的限制!跑到于a同一層了!因為函數(shù)只認它們在定義時所處的環(huán)境(而不是執(zhí)行時,這點很重要),N中的c仍然可以訪問b!此時的a還是不可以訪問b!
但是這是怎么實現(xiàn)的呢?如下:
閉包1:
function f(){
var b = "b";
return function(){ //沒有名字的函數(shù),所以是匿名函數(shù)
return b;
}
}
注意返回的函數(shù)可以訪問它父親函數(shù)中的變量b
此時如果你想取b的值,當(dāng)然是undefined
但是如果你這么做:
var n = f();
n();
你可以取到b的值了!雖然此時n函數(shù)在f的外面,b又屬于f內(nèi)部的變量,但是f內(nèi)部出了一個內(nèi)鬼,返回了b的值……
現(xiàn)在大家有點感覺了吧
閉包2:
var n;
function f(){
var b = "b";
n = function(){
return b;
}
}
如果此時調(diào)用f會怎么樣?那就生成了一個n的全局范圍函數(shù),但是它卻能訪問f的內(nèi)部,照樣返回b的值,與上面有異曲同工之妙!
閉包3:
你還可以用閉包訪問函數(shù)的參數(shù)
function f(arg) {
var n = function(){
return arg;
};
arg++;
return n;
}
此時如果使用:
var m = f(123);
m();
結(jié)果是124
因為此時f中返回的匿名函數(shù)經(jīng)過了兩道轉(zhuǎn)手,先給n,再賦給外面的m,但本質(zhì)沒有變,把定義時父函數(shù)的參數(shù)返回了
閉包4:
var getValue, setValue;
function() {
var secret = 0;
getValue = function(){
return secret;
};
setValue = function(v){
secret = v;
};
})
運行:
getValue()
0
setValue(123)
getValue()
123
這個就不用解釋了吧,如果你有面向?qū)ο笳Z言基礎(chǔ)的話(如C#),這里的getValue和setValue就類似于一個對象的屬性訪問器,你可以通過這兩個訪問器來賦值和取值,而不是能訪問其中內(nèi)容
其實書中還有幾個閉包的例子,但是原理用上面四個就足夠了,希望能起拋磚引玉的作用,給javascript進階者對閉包有一個更深刻的理解
- javascript閉包的高級使用方法實例
- JavaScript自執(zhí)行閉包的小例子
- 深入Javascript函數(shù)、遞歸與閉包(執(zhí)行環(huán)境、變量對象與作用域鏈)使用詳解
- 談?wù)凧avaScript中的函數(shù)與閉包
- 深入理解JavaScript 閉包究竟是什么
- JavaScript中的作用域鏈和閉包
- javascript學(xué)習(xí)筆記(十三) js閉包介紹(轉(zhuǎn))
- Javascript 閉包引起的IE內(nèi)存泄露分析
- 深入理解JavaScript系列(16) 閉包(Closures)
- JavaScript 高級篇之閉包、模擬類,繼承(五)
- JavaScript高級程序設(shè)計 讀書筆記之八 Function類及閉包
- javaScript 利用閉包模擬對象的私有屬性
- JavaScript閉包 懂不懂由你反正我是懂了
- JavaScript 匿名函數(shù)(anonymous function)與閉包(closure)
- javascript的閉包介紹(司徒正美)
- javascript 閉包
- Javascript閉包演示代碼小結(jié)
- 基于javascript 閉包基礎(chǔ)分享
相關(guān)文章
javascript json字符串到j(luò)son對象轉(zhuǎn)義問題
今天小編就為大家分享一篇關(guān)于javascript json字符串到j(luò)son對象轉(zhuǎn)義問題,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-01-01微信小程序wx.request實現(xiàn)后臺數(shù)據(jù)交互功能分析
這篇文章主要介紹了微信小程序wx.request實現(xiàn)后臺數(shù)據(jù)交互功能,分析微信小程序wx.request在后臺數(shù)據(jù)交互過程中遇到的問題與相關(guān)的解決方法,需要的朋友可以參考下2017-11-11微信小程序?qū)崿F(xiàn)簡單手寫簽名組件的方法實例
在使用微信的時候,為方便我們發(fā)送文件可以直接在上面進行手寫簽名,這篇文章主要給大家介紹了關(guān)于利用微信小程序?qū)崿F(xiàn)簡單手寫簽名組件的相關(guān)資料,需要的朋友可以參考下2021-07-07uni-app使用uploadFile上傳多張圖片的具體實現(xiàn)
在微信小程序中不支持多張圖片上傳,需要做循環(huán)實現(xiàn)多張圖片上傳,下面這篇文章主要給大家介紹了關(guān)于uni-app使用uploadFile上傳多張圖片的具體實現(xiàn),需要的朋友可以參考下2023-04-04JavaScript 無縫上下左右滾動加定高定寬停頓效果(兼容ie/ff)
JavaScript 指定寬度高度的無間斷滾動實現(xiàn)代碼,這樣的效果適合作為焦點新聞的輪播顯示。2010-03-03實現(xiàn)web打印的各種方法介紹及實現(xiàn)代碼
web的打印方法具我自己懂得知道的有:JQuery插件Jqprint實現(xiàn);JQery打印插件PrintArea實現(xiàn)網(wǎng)頁打印;CSS控制網(wǎng)頁打印樣式,本文詳細介紹實現(xiàn)步驟,感興趣的朋友可以了解下2013-01-01