摘要:下面我們就初步嘗試一下閉包現(xiàn)在來看一下發(fā)生了什么。于是,這種結(jié)構(gòu)就被稱作閉包。這就是閉包強大的地方。例如,如果我們可以在我們的計數(shù)器里面加一個名字我們可以往閉包里傳一個參數(shù)可以看出來,在實現(xiàn)過程中不僅能記住局部變量,也記住了傳進來的變量。
計數(shù)器
首先,從一個計數(shù)器開始。
var counter = 0; function increment() { counter = counter + 1; console.log("Number of events: " + counter); }
increment(); // Number of events: 1 increment(); // Number of events: 2 increment(); // Number of events: 3多個計數(shù)器
上面的代碼簡單粗暴,但是我們很快會遇到下一個問題:如果想要再創(chuàng)建一個計數(shù)器怎么辦呢。當然我們可以創(chuàng)建兩個變量,兩個函數(shù),但這樣是不是太low了:
var counter1 = 0; function incrementCounter1() { counter1 = counter1 + 1; console.log("Number of events: " + counter1); } var counter2 = 0; function incrementCounter2() { counter2 = counter2 + 1; console.log("Number of events: " + counter2); } incrementCounter1(); // Number of events: 1 incrementCounter2(); // Number of events: 1 incrementCounter1(); // Number of events: 2
而且當需要更多的計數(shù)器時,就更不可能用這種方法了。
引入閉包上面的那段代碼,我們更想做的是封裝成一個函數(shù),去除冗余代碼。下面我們就初步嘗試一下閉包:
function createCounter() { var counter = 0; function increment() { counter = counter + 1; console.log("Number of events: " + counter); } return increment; }
現(xiàn)在來看一下發(fā)生了什么。我們將會創(chuàng)建兩個計數(shù)器,并且使用它們來跟蹤兩個獨立的事件:
var counter1 = createCounter(); var counter2 = createCounter(); counter1(); // Number of events: 1 counter1(); // Number of events: 2 counter2(); // Number of events: 1 counter1(); // Number of events: 3
額,看起來有點復雜。。但實際上很簡單。我們只需要分解一下實現(xiàn)的邏輯。
首先,創(chuàng)建了一個局部變量counter
然后,創(chuàng)建了一個局部函數(shù)increment,可以增加counter的值。
其實這個createCounter()的實現(xiàn)幾乎跟最開始那個計數(shù)器一樣。唯一不同的就是它被函數(shù)包裹起來了。于是,這種結(jié)構(gòu)就被稱作閉包。
然后就到了最重要的地方:
createCounter()里的最后一步 返回了 increment局部函數(shù) ,注意,這里返回的不是函數(shù)的調(diào)用結(jié)果,而是函數(shù)本身。
這也就是說,當我們使用下面的語句創(chuàng)建計數(shù)器,我們實際上是生成了一個新的函數(shù)。
// fancyNewCounter is a function in this scope var fancyNewCounter = createCounter();
這就是閉包強大的地方。每個通過createCounter()生成的函數(shù)都保持追蹤它們自己產(chǎn)生的counter的值。也就是說,這個返回的函數(shù)會記住他被創(chuàng)建時的環(huán)境。
可以看到的重要的一點就是內(nèi)部的counter變量都是互相獨立的。創(chuàng)建了兩個計數(shù)器,它們會各自在閉包中分配一個新的counter變量。我們可以看到:
每個計數(shù)器都從1開始計數(shù):
var counter1 = createCounter(); counter1(); // Number of events: 1 counter1(); // Number of events: 2 var counter2 = createCounter(); counter2(); // Number of events: 1
第二個計數(shù)器沒有收到第一個計數(shù)器的值的影響。
counter1(); // Number of events: 3命名我們的計數(shù)器
“Number of events: x”這種消息是可以的,但是如果信息可以描述我們正在計數(shù)的事件的類型,會不會更好。例如,如果我們可以在我們的計數(shù)器里面加一個名字:
var catCounter = createCounter("cats"); var dogCounter = createCounter("dogs"); catCounter(); // Number of cats: 1 catCounter(); // Number of cats: 2 dogCounter(); // Number of dogs: 1
我們可以往閉包里傳一個參數(shù)
function createCounter(counterName) { var counter = 0; function increment() { counter = counter + 1; console.log("Number of " + counterName + ": " + counter); } return increment; }
可以看出來,createCounter在實現(xiàn)過程中不僅能記住局部變量counter,也記住了傳進來的變量。
優(yōu)化公共接口上面的寫法有個問題就是,當我們在執(zhí)行計數(shù)器的時候,很難直觀的看出來這個計數(shù)器是個將要計算增量的函數(shù),下面的寫法會更簡潔:
var dogCounter = createCounter("dogs"); dogCounter.increment(); // Number of dogs: 1
function createCounter(counterName) { var counter = 0; function increment() { counter = counter + 1; console.log("Number of " + counterName + ": " + counter); }; return { increment : increment }; }
在上面的代碼中,我們返回了一個包含閉包中所有函數(shù)的對象。從某種意義上來說,我們正在定義我們的閉包可以響應的一系列消息
添加遞減現(xiàn)在我們可以非常簡單的將遞減的函數(shù)加入到計數(shù)器中。
function createCounter(counterName) { var counter = 0; function increment() { counter = counter + 1; console.log("Number of " + counterName + ": " + counter); }; function decrement() { counter = counter - 1; console.log("Number of " + counterName + ": " + counter); }; return { increment : increment, decrement : decrement }; } var dogsCounter = createCounter("dogs"); dogsCounter.increment(); // Number of dogs: 1 dogsCounter.increment(); // Number of dogs: 2 dogsCounter.decrement(); // Number of dogs: 1隱藏計數(shù)動作
上面的代碼的console.log重復了兩次。應該明確的創(chuàng)建一個函數(shù)來顯示計數(shù)器的值。
function createCounter(counterName) { var counter = 0; function display() { console.log("Number of " + counterName + ": " + counter); } function increment() { counter = counter + 1; display(); }; function decrement() { counter = counter - 1; display(); }; return { increment : increment, decrement : decrement }; } var dogsCounter = createCounter("dogs"); dogsCounter.increment(); // Number of dogs: 1 dogsCounter.increment(); // Number of dogs: 2 dogsCounter.decrement(); // Number of dogs: 1
display函數(shù)看起來和increment()和decrement()很像的樣子,但其實是非常不同的。我們沒有在對象的結(jié)果中返回這個函數(shù),也就是說下面的語句會報錯:
var dogsCounter = createCounter("dogs"); dogsCounter.display(); // ERROR !!!
我們讓display()函數(shù)從外面的世界隱藏了,它只供createCounter()內(nèi)部訪問
抽象數(shù)據(jù)類型讓我們使用閉包來實現(xiàn)棧操作
function createStack() { var elements = []; return { push: function(el) { elements.unshift(el); }, pop: function() { return elements.shift(); } }; } var stack = createStack(); stack.push(3); stack.push(4); stack.pop(); // 4
注意:在Javascript中,閉包可能并不是實現(xiàn)棧數(shù)據(jù)類型的最佳實現(xiàn)方式,Prototypes可能會更好一些
閉包和OOP如果你做過面向?qū)ο缶幊蹋憧赡軙⒁獾剑厦娴慕Y(jié)構(gòu)特別像類啊對象啊實例變量和公有/私有方法。
按:好久沒翻譯了,這篇文章翻譯的有些智障,但是不耽誤看代碼,看完還是很有收獲的!
英文原文:http://renderedtext.com/blog/...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/84608.html
摘要:前端日報精選專題之通用遍歷方法的實現(xiàn)深入了解的子組件上最流行的項目再聊移動端頁面的適配譯盒子模型實踐教程中文全棧第天數(shù)據(jù)驅(qū)動龍云全棧譯年開發(fā)趨勢瘋狂的技術(shù)宅在翻譯譯閉包并不神秘前端心得拼多多前端筆試個人文章容器技術(shù)方 2017-08-03 前端日報 精選 JavaScript專題之jQuery通用遍歷方法each的實現(xiàn)深入了解React的子組件GitHub上最流行的Top 10 Jav...
摘要:原文地址下面是中文翻譯擁有強大的控制反轉(zhuǎn)依賴注入容器。單例在使用自動綁定和時,每次需要時都會創(chuàng)建一個新的實例或者調(diào)用閉包。 原文地址 Laravels Dependency Injection Container in Depth 下面是中文翻譯 Laravel擁有強大的控制反轉(zhuǎn)(IoC)/依賴注入(DI) 容器。不幸的是官方文檔并沒有涵蓋所有可用的功能,因此,我決定嘗試寫文檔為自...
摘要:在中閉包已經(jīng)成了一個很神秘,讓人高山仰止的存在。今天又對閉包進行了一番搜索,有了一種明悟閉包就相當于黑盒的鑰匙。當你手握閉包,黑盒就能為你所用。通過訪問外部變量,一個閉包可以維持這些變量。閉包經(jīng)常用于創(chuàng)建含有隱藏數(shù)據(jù)的函數(shù)但并不總是這樣。 在javascript中閉包已經(jīng)成了一個很神秘,讓人高山仰止的存在。 今天又對閉包進行了一番搜索,有了一種明悟:閉包就相當于黑盒的鑰匙。當你手握閉包...
摘要:它到底是什么,是作用于數(shù)據(jù)的結(jié)構(gòu)嗎這同樣是一個模棱兩可的術(shù)語。最后我還是搞清楚了數(shù)據(jù)結(jié)構(gòu)的概念,那就簡單的把術(shù)語數(shù)據(jù)結(jié)構(gòu)稱為數(shù)據(jù)的結(jié)構(gòu)。目標數(shù)據(jù)結(jié)構(gòu)系列技術(shù)文章,會告訴你數(shù)據(jù)結(jié)構(gòu)并不是晦澀難懂的,更不是神秘的。 翻譯:瘋狂的技術(shù)宅英文:https://code.tutsplus.com/tut...說明:本文翻譯自系列文章《Data Structures With JavaScrip...
摘要:準確的說,是形成了的閉包。因此對象函數(shù)也是對象和控制流能通過閉包實現(xiàn)。這種方式的閉包不再具有引用透明性,即他不再是一個純函數(shù)。類閉包結(jié)構(gòu)一些語言的特性能夠模擬出閉包的效果。 寫在開頭 ?本來是很討厭談論閉包這個話題的,因為在這一方面我比較傾向于玉伯還有一些朋友的觀點,搞懂作用域才是最重要的,單獨談論閉包,真的意義不大。 ?今天剛好在wiki上查其他東西的時候看到了,想了想以前也沒從比較...
閱讀 970·2022-06-21 15:13
閱讀 1855·2021-10-20 13:48
閱讀 1039·2021-09-22 15:47
閱讀 1373·2019-08-30 15:55
閱讀 3128·2019-08-30 15:53
閱讀 526·2019-08-29 12:33
閱讀 721·2019-08-28 18:15
閱讀 3467·2019-08-26 13:58