最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

用最通俗易懂的代碼幫助新手理解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ù)雜,有興趣的朋友可以看看,適合想進(jìn)階的朋友。
今天就結(jié)合這兩本書,用最淺顯的語言和最通俗的方式談?wù)刯avascript中的閉包,因為也是新手,所以有有誤的地方請各位指出,謝謝
一. 準(zhǔn)備知識
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ù)傳遞進(jìn)去了,并且在第一個循環(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ù)只認(rèn)它們在定義時所處的環(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進(jìn)階者對閉包有一個更深刻的理解

相關(guān)文章

  • Express實現(xiàn)前端后端通信上傳圖片之存儲數(shù)據(jù)庫(mysql)傻瓜式教程(二)

    Express實現(xiàn)前端后端通信上傳圖片之存儲數(shù)據(jù)庫(mysql)傻瓜式教程(二)

    這篇文章主要介紹了Express實現(xiàn)前端后端通信上傳圖片之存儲數(shù)據(jù)庫(mysql)傻瓜教程(二)的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • 微信小程序?qū)崿F(xiàn)商品分類頁過程結(jié)束

    微信小程序?qū)崿F(xiàn)商品分類頁過程結(jié)束

    這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)商品分類頁列表方法,商品分類頁主要是需要實現(xiàn)商品類目和對應(yīng)商品標(biāo)題的聯(lián)動跳轉(zhuǎn),文中過程詳細(xì),感興趣的小伙伴們可以參考一下
    2023-05-05
  • 14 個折磨人的 JavaScript 面試題

    14 個折磨人的 JavaScript 面試題

    這篇文章主要為大家詳細(xì)介紹了14 個折磨人的 JavaScript 面試題,希望對大家有所幫助,感興趣的小伙伴們可以參考一下
    2016-08-08
  • JavaScrip實現(xiàn)圖片壓縮與分辨率等比例縮放

    JavaScrip實現(xiàn)圖片壓縮與分辨率等比例縮放

    這篇文章主要為大家詳細(xì)介紹了如何使用JavaScrip實現(xiàn)圖片壓縮與分辨率等比例縮放,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • TypeScript 中的 .d.ts 文件詳解(加強類型支持提升開發(fā)效率)

    TypeScript 中的 .d.ts 文件詳解(加強類型支持提升開發(fā)效率)

    .d.ts 文件在 TypeScript 開發(fā)中扮演著非常重要的角色,它們讓我們能夠享受到 TypeScript 強大的類型系統(tǒng)帶來的優(yōu)勢,提高代碼質(zhì)量和開發(fā)效率,接下來,我們將深入探討如何為 JavaScript 庫和自定義模塊創(chuàng)建 .d.ts 文件,以及一些最佳實踐和注意事項,一起看看吧
    2023-09-09
  • H5 js點擊按鈕復(fù)制文本到粘貼板

    H5 js點擊按鈕復(fù)制文本到粘貼板

    這篇文章主要為大家詳細(xì)介紹了H5 js點擊按鈕復(fù)制文本到粘貼板,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • 前端使用國密sm2和sm4進(jìn)行加解密代碼示例

    前端使用國密sm2和sm4進(jìn)行加解密代碼示例

    在前端實現(xiàn)加密算法時,需要特別注意密鑰的安全存儲和管理,不應(yīng)將敏感的密鑰硬編碼在前端代碼中,這篇文章主要介紹了前端使用國密sm2和sm4進(jìn)行加解密的相關(guān)資料,需要的朋友可以參考下
    2025-04-04
  • 微信小程序?qū)崙?zhàn)之自定義toast(6)

    微信小程序?qū)崙?zhàn)之自定義toast(6)

    這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崙?zhàn)之自定義toast的相關(guān)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • async/await實現(xiàn)Promise.acll()簡介

    async/await實現(xiàn)Promise.acll()簡介

    Promise.all() 方法接收一個 promise 的 iterable 類型的輸入,并且只返回一個Promise實例,并且輸入的所有 promise 的 resolve 回調(diào)的結(jié)果是一個數(shù)組,這篇文章主要介紹了async/await實現(xiàn)Promise.acll()簡介,需要的朋友可以參考下
    2022-11-11
  • javascript管中窺豹 形參與實參淺析

    javascript管中窺豹 形參與實參淺析

    本想從語言的角度來分析,無奈功力不夠,只能粗淺的嘗試一下,于是稱之管中窺豹,還望大牛指正
    2011-12-12

最新評論

汽车| 秦安县| 旺苍县| 弥渡县| 自贡市| 托里县| 洛阳市| 阿荣旗| 渑池县| 申扎县| 大厂| 菏泽市| 长治市| 五莲县| 中卫市| 吉安县| 汤阴县| 南康市| 东阿县| 铅山县| 洪湖市| 临颍县| 汾西县| 紫阳县| 岢岚县| 元朗区| 都匀市| 宜宾县| 青岛市| 南通市| 托克逊县| 青河县| 齐河县| 扎鲁特旗| 营口市| 马龙县| 文登市| 那曲县| 泾川县| 盐山县| 利津县|