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

理解javascript函數(shù)式編程中的閉包(closure)

 更新時(shí)間:2016年03月08日 10:23:08   作者:LAVERTON  
這篇文章主要幫助大家理解javascript函數(shù)式編程中的閉包(closure)概念,通俗地講, JavaScript 中每個(gè)的函數(shù)都是一個(gè)閉包,感興趣的小伙伴們可以參考一下

閉包(closure)是函數(shù)式編程中的概念,出現(xiàn)于 20 世紀(jì) 60 年代,最早實(shí)現(xiàn)閉包的語言是 Scheme,它是 LISP 的一種方言。之后閉包特性被其他語言廣泛吸納。
閉包的嚴(yán)格定義是“由函數(shù)(環(huán)境)及其封閉的自由變量組成的集合體?!边@個(gè)定義對于大家來說有些晦澀難懂,所以讓我們先通過例子和不那么嚴(yán)格的解釋來說明什么是閉包,然后再舉例說明一些閉包的經(jīng)典用途。

什么是閉包

通俗地講, JavaScript 中每個(gè)的函數(shù)都是一個(gè)閉包,但通常意義上嵌套的函數(shù)更能夠體
現(xiàn)出閉包的特性,請看下面這個(gè)例子:

var generateClosure = function() {
var count = 0;
var get = function() {
count ++;
return count;
};
return get;
};
var counter = generateClosure();
console.log(counter()); // 輸出 1
console.log(counter()); // 輸出 2
console.log(counter()); // 輸出 3

這段代碼中, generateClosure() 函數(shù)中有一個(gè)局部變量count, 初值為 0。還有一個(gè)叫做 get 的函數(shù), get 將其父作用域,也就是 generateClosure() 函數(shù)中的 count 變量增加 1,并返回 count 的值。 generateClosure() 的返回值是 get 函數(shù)。在外部我們通過 counter 變量調(diào)用了 generateClosure() 函數(shù)并獲取了它的返回值,也就是 get 函數(shù),接下來反復(fù)調(diào)用幾次 counter(),我們發(fā)現(xiàn)每次返回的值都遞增了 1。
讓我們看看上面的例子有什么特點(diǎn),按照通常命令式編程思維的理解, count 是generateClosure 函數(shù)內(nèi)部的變量,它的生命周期就是 generateClosure 被調(diào)用的時(shí)期,當(dāng) generateClosure 從調(diào)用棧中返回時(shí), count 變量申請的空間也就被釋放。問題是,在 generateClosure() 調(diào)用結(jié)束后, counter() 卻引用了“已經(jīng)釋放了的” count變量,而且非但沒有出錯,反而每次調(diào)用 counter() 時(shí)還修改并返回了 count。這是怎么回事呢?
這正是所謂閉包的特性。當(dāng)一個(gè)函數(shù)返回它內(nèi)部定義的一個(gè)函數(shù)時(shí),就產(chǎn)生了一個(gè)閉包,閉 包 不 但 包 括 被 返 回 的 函 數(shù) , 還包括這個(gè)函數(shù)的定義環(huán)境。上面例子中,當(dāng)函數(shù)generateClosure() 的內(nèi)部函數(shù) get 被一個(gè)外部變量 counter 引用時(shí), counter 和generateClosure() 的局部變量就是一個(gè)閉包。如果還不夠清晰,下面這個(gè)例子可以幫助
你理解:

var generateClosure = function() {
var count = 0;
var get = function() {
count ++;
return count;
};
return get;
};
var counter1 = generateClosure();
var counter2 = generateClosure();
console.log(counter1()); // 輸出 1
console.log(counter2()); // 輸出 1
console.log(counter1()); // 輸出 2
console.log(counter1()); // 輸出 3
console.log(counter2()); // 輸出 2

上面這個(gè)例子解釋了閉包是如何產(chǎn)生的:counter1 和 counter2 分別調(diào)用了 generateClosure() 函數(shù),生成了兩個(gè)閉包的實(shí)例,它們內(nèi)部引用的 count 變量分別屬于各自的運(yùn)行環(huán)境。我們可以理解為,在generateClosure() 返回 get 函數(shù)時(shí),私下將 get 可能引用到的 generateClosure() 函數(shù)的內(nèi)部變量(也就是 count 變量)也返回了,并在內(nèi)存中生成了一個(gè)副本,之后 generateClosure() 返回的函數(shù)的兩個(gè)實(shí)例 counter1和 counter2 就是相互獨(dú)立的了。

閉包的用途

1、嵌套的回調(diào)函數(shù)
閉包有兩個(gè)主要用途,一是實(shí)現(xiàn)嵌套的回調(diào)函數(shù),二是隱藏對象的細(xì)節(jié)。讓我們先看下面這段代碼示例,了解嵌套的回調(diào)函數(shù)。如下代碼是在 Node.js 中使用 MongoDB 實(shí)現(xiàn)一個(gè)簡單的增加用戶的功能:

exports.add_user = function(user_info, callback) {
var uid = parseInt(user_info['uid']);
mongodb.open(function(err, db) {
if (err) {callback(err); return;}
db.collection('users', function(err, collection) {
if (err) {callback(err); return;}
collection.ensureIndex("uid", function(err) {
if (err) {callback(err); return;}
collection.ensureIndex("username", function(err) {
if (err) {callback(err); return;}
collection.findOne({uid: uid}, function(err) {
if (err) {callback(err); return;}
if (doc) {
callback('occupied');
} else {
var user = {
uid: uid,
user: user_info,
};
collection.insert(user, function(err) {
callback(err);
});
}
});
});
});
});
});
};

如果你對 Node.js 或 MongoDB 不熟悉,沒關(guān)系,不需要去理解細(xì)節(jié),只要看清楚大概的邏輯即可。這段代碼中用到了閉包的層層嵌套,每一層的嵌套都是一個(gè)回調(diào)函數(shù)?;卣{(diào)函數(shù)不會立即執(zhí)行,而是等待相應(yīng)請求處理完后由請求的函數(shù)回調(diào)。我們可以看到,在嵌套的每一層中都有對 callback 的引用,而且最里層還用到了外層定義的 uid 變量。由于閉包機(jī)制的存在,即使外層函數(shù)已經(jīng)執(zhí)行完畢,其作用域內(nèi)申請的變量也不會釋放,因?yàn)槔飳拥暮瘮?shù)還有可能引用到這些變量,這樣就完美地實(shí)現(xiàn)了嵌套的異步回調(diào)。

2、實(shí)現(xiàn)私有成員
我們知道, JavaScript 的對象沒有私有屬性,也就是說對象的每一個(gè)屬性都是曝露給外部的。這樣可能會有安全隱患,譬如對象的使用者直接修改了某個(gè)屬性,導(dǎo)致對象內(nèi)部數(shù)據(jù)的一致性受到破壞等。 JavaScript通過約定在所有私有屬性前加上下劃線(例如_myPrivateProp),表示這個(gè)屬性是私有的,外部對象不應(yīng)該直接讀寫它。但這只是個(gè)非正式的約定,假設(shè)對象的使用者不這么做,有沒有更嚴(yán)格的機(jī)制呢?答案是有的,通過閉包可以實(shí)現(xiàn)。讓我們再看看前面那個(gè)例子:

var generateClosure = function() {
var count = 0;
var get = function() {
count ++;
return count;
};
return get;
};
var counter = generateClosure();
console.log(counter()); // 輸出 1
console.log(counter()); // 輸出 2
console.log(counter()); // 輸出 3

我們可以看到,只有調(diào)用 counter() 才能訪問到閉包內(nèi)的 count 變量,并按照規(guī)則對其增加1,除此之外決無可能用其他方式找到 count 變量。受到這個(gè)簡單例子的啟發(fā),我們可以把一個(gè)對象用閉包封裝起來,只返回一個(gè)“訪問器”的對象,即可實(shí)現(xiàn)對細(xì)節(jié)隱藏。

以上就是本文的全部內(nèi)容,希望能夠幫助大家更好的學(xué)習(xí)理解javascript閉包。

相關(guān)文章

  • 純原生js實(shí)現(xiàn)貪吃蛇游戲

    純原生js實(shí)現(xiàn)貪吃蛇游戲

    這篇文章主要為大家詳細(xì)介紹了純原生js實(shí)現(xiàn)貪吃蛇游戲的相關(guān)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • js 中將多個(gè)逗號替換為一個(gè)逗號的代碼

    js 中將多個(gè)逗號替換為一個(gè)逗號的代碼

    這篇文章主要介紹了js 中將多個(gè)逗號替換為一個(gè)逗號的代碼,需要的朋友可以參考下
    2014-06-06
  • JS原生瀑布流效果實(shí)現(xiàn)

    JS原生瀑布流效果實(shí)現(xiàn)

    這篇文章主要介紹了JS原生瀑布流效果實(shí)現(xiàn) ,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • JavaScript實(shí)現(xiàn)圖片切換效果

    JavaScript實(shí)現(xiàn)圖片切換效果

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)圖片切換效果,以及自定義屬性的應(yīng)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • js判斷PC端與移動端跳轉(zhuǎn)

    js判斷PC端與移動端跳轉(zhuǎn)

    本文主要介紹了js判斷PC端與移動端跳轉(zhuǎn)的方法,具有很好的參考價(jià)值。下面跟著小編一起來看下吧
    2017-03-03
  • ES6記錄異步函數(shù)的執(zhí)行時(shí)間詳解

    ES6記錄異步函數(shù)的執(zhí)行時(shí)間詳解

    在這篇文章里,我會實(shí)現(xiàn)一個(gè)可重用的函數(shù)來處理 JavaScript 延時(shí)異步操作。有需要的小伙伴們可以參考借鑒,下面來一起看看。
    2016-08-08
  • 使用focus方法讓光標(biāo)默認(rèn)停留在INPUT框

    使用focus方法讓光標(biāo)默認(rèn)停留在INPUT框

    讓光標(biāo)默認(rèn)停留在INPUT框中,用focus方法可以實(shí)現(xiàn),下面有個(gè)示例代碼,需要的朋友可以參考下
    2014-07-07
  • IE innerHTML,outerHTML所引起的問題

    IE innerHTML,outerHTML所引起的問題

    我們在用javascript創(chuàng)建一個(gè)遮蓋層(div)后,如果點(diǎn)擊關(guān)閉用到了
    2009-06-06
  • JavaScript獲取上傳進(jìn)度的幾種方式實(shí)現(xiàn)

    JavaScript獲取上傳進(jìn)度的幾種方式實(shí)現(xiàn)

    進(jìn)度條的應(yīng)用是為了顯示的告訴用戶文件上傳了多少,本文主要介紹了JavaScript獲取上傳進(jìn)度的幾種方式,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • 定時(shí)器(setTimeout/setInterval)調(diào)用帶參函數(shù)失效解決方法

    定時(shí)器(setTimeout/setInterval)調(diào)用帶參函數(shù)失效解決方法

    setInterval()方法可按照指定的周期(以毫秒計(jì))來調(diào)用函數(shù)或計(jì)算表達(dá)式,setTimeout()方法用于在指定的毫秒數(shù)后調(diào)用函數(shù)或計(jì)算表達(dá)式,詳細(xì)使用方法可以參考下本文
    2013-03-03

最新評論