摘要:閉包在我理解是一種比較抽象的東西。所以我寫了一篇博文來方便自己理解閉包。那么現(xiàn)在我們可以解釋一下閉包的第一個定義在計算機科學中,閉包是引用了自由變量的函數(shù)。循環(huán)中創(chuàng)建閉包在我們使用的關(guān)鍵字之前,閉包的一個常見問題就出現(xiàn)在循環(huán)中創(chuàng)建閉包。
零. 前言
從我開始接觸前端時就聽說過閉包,但是一直不理解閉包究竟是什么。上網(wǎng)看了各種博客,大家對閉包的說法不一。閉包在我理解是一種比較抽象的東西。所以我寫了一篇博文來方便自己理解閉包。博主是第一次寫博文,如果在文章中有什么看不懂或者概念錯誤的地方,請大家多多見諒和指出錯誤。
一. 閉包的定義再說閉包之前,首先讓我們先來理解一下自由變量和約束變量。
在程序設(shè)計語言中,變量可以分為自由變量與約束變量兩種。簡單來說,一個函數(shù)里局部變量和參數(shù)都被認為是約束變量;而不是約束變量的則是自由變量。下面我們通過一個demo來解說。
var x = 10; // 相對于fn來說,x是一個自由變量 function fn(){ var b = 20; console.log( x + b ); // 30 } fn();
在上述例子中,相對于函數(shù)實例fn而言,x是一個自由變量,因為x并不是fn的局部變量和參數(shù)。而b是fn的局部參數(shù),所以b是fn的約束變量。
那么現(xiàn)在我們可以解釋一下閉包的第一個定義:
在計算機科學中,閉包是引用了自由變量的函數(shù)。
其實閉包不一定要是函數(shù)實例,也可以是代碼塊,只要滿足可以保存變量在內(nèi)存,同時有一些方法對于這些變量進行訪問就行了。
所以,我們可以引申出閉包的第二個定義:
閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實例,環(huán)境由閉包創(chuàng)建時在作用域中的任何局部變量和參數(shù)組成。
閉包在運行時可以有多個實例,不同的引用環(huán)境和相同的函數(shù)組合可以產(chǎn)生不同的實例。
// 例子1 function Person(){ var name, age; function init(name, age){ name = name; age = age; } function show(){ console.log("name: %s, age: %d", name, age); } return { init: init, show: show } } var eyesiM = Person.init("EyesiM", 22); // 閉包的實例1 var dcc = Person.init("Dcc", 20); // 閉包的實例2 eyesiM.show(); // name: EyesiM, age: 22 dcc.show(); // name: Dcc, age: 20
上面的變量eyesiM和變量dcc就是閉包的實例,其中變量eyesiM的環(huán)境中局部變量name和age的值為"EyesiM"和22;變量dcc的環(huán)境中的局部變量name和age的值為"Dcc"和20。
二. 閉包的應用閉包可以用來在一個函數(shù)與一組“私有”變量之間建立關(guān)聯(lián)關(guān)系。在給定函數(shù)被多次調(diào)用的過程中,這些私有變量能夠保存在內(nèi)存中。變量的作用域僅限于包含它們的函數(shù),因此無法從除包含它們的函數(shù)之外進行訪問。
1. 模塊模式在Java等等一些語言里面會有private關(guān)鍵字來將方法和變量聲明為私有的,即它們只能被同一個類中的其它方法所調(diào)用。
JavaScript不提供原生的支持,但是可以使用閉包模擬私有變量和私有方法。私有變量可以限制對代碼的訪問;避免非核心的方法弄亂了代碼的公共接口部分。
// 例子2 var demo = (function(){ // 模擬私有變量 var count = 0; function show(){ console.log("count: %d", count++); } return { show: show } })(); demo.show(); // 0 demo.count; // 我們不能直接引用,所以這里會返回undefined
在我理解,模塊模式可以有兩種用途:
立即調(diào)用函數(shù)表達式(IIFE):將我們自身的變量和方法封裝起來,可以避免全局污染。例子2就是一個IIFE的例子。
引入依賴:我們可以引入對某一個全局對象的依賴,對這一個全局進行擴充。下面我們可以通過一個例子來表示。
// MODULE 就是一個全局對象,如果不存在就初始化為`{}`,我們使用局部參數(shù)my指向這個對象,接著我們給這個全局對象添加屬性`method`,然后返回指向這個全局對象的引用。 var MODULE = (function (my) { my.method = { // add code } return my; }(MODULE || {}));2. 循環(huán)中創(chuàng)建閉包
在我們使用ES6的let關(guān)鍵字之前,閉包的一個常見問題就出現(xiàn)在循環(huán)中創(chuàng)建閉包。
// 例子3Document applebananaorange
function showColor(item) { console.log("id: %s, color: %s", item.id, item.color); } function addHTML() { var colors = [{ id: "apple", color: "red" }, { id: "banana", color: "yellow" }, { id: "orange", color: "orange" }]; for (var i = 0, length = colors.length; i < length; i++) { var item = colors[i]; // error // 當我們把鼠標依次移過id為"apple", "banana", "orange"的div時,控制臺打印出的是 // id: orange, color: orange // id: orange, color: orange // id: orange, color: orange // document.getElementById(item.id).onmouseover = function(){ // showColor(item); // } // success // 當我們把鼠標依次移過id為"apple", "banana", "orange"的div時,控制臺打印出的是 // id: apple, color: red // id: banana, color: yellow // id: orange, color: orange document.getElementById(item.id).onmouseover = function(item) { return function() { showColor(item); }; }(item); } } addHTML();三. 閉包的注意點
閉包避免了環(huán)境中的變量被當成垃圾回收,因此使用閉包會使得閉包中的變量都被保存在內(nèi)存中。
在一般的多頁面中,我們關(guān)閉或重定向了頁面之后,瀏覽器會自動回收原頁面所占用的資源,但是如果我們所做的項目是SPA的話,就需要考慮到內(nèi)存的使用,所以一定要慎用閉包。
四. 參考資料yangfch3的筆記-閉包
深入理解JavaScript 模塊模式
詳解javascript立即執(zhí)行函數(shù)表達式(IIFE)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/80585.html
摘要:譯者按在上一篇博客,我們通過實現(xiàn)一個計數(shù)器,了解了如何使用閉包,這篇博客將提供一些代碼示例,幫助大家理解閉包。然而,如果通過代碼示例去理解閉包,則簡單很多。不過,將閉包簡單地看做局部變量,理解起來會更加簡單。 - 譯者按: 在上一篇博客,我們通過實現(xiàn)一個計數(shù)器,了解了如何使用閉包(Closure),這篇博客將提供一些代碼示例,幫助大家理解閉包。 原文: JavaScript Clos...
摘要:閉包是函數(shù)內(nèi)部的子函數(shù)能讀取局部變量二閉包的特點函數(shù)里面嵌套函數(shù)內(nèi)部函數(shù)能訪問外部函數(shù)的變量定義的參數(shù)和變量不會回收三閉包的前提先明白什么是全局變量和局部變量中聲明變量格式關(guān)鍵字變量名標識符。建議在退出函數(shù)之前,將不使用的局部變量全部刪除。 一、閉包的概念 閉包是指一個函數(shù)能夠訪問其函數(shù)外部作用域中的變量。JavaScript閉包是函數(shù)內(nèi)部的子函數(shù)能讀取局部變量 二、閉包的特點 函數(shù)...
摘要:一言以蔽之,閉包,你就得掌握。當函數(shù)記住并訪問所在的詞法作用域,閉包就產(chǎn)生了。所以閉包才會得以實現(xiàn)。從技術(shù)上講,這就是閉包。執(zhí)行后,他的內(nèi)部作用域并不會消失,函數(shù)依然保持有作用域的閉包。 網(wǎng)上總結(jié)閉包的文章已經(jīng)爛大街了,不敢說筆者這篇文章多么多么xxx,只是個人理解總結(jié)。各位看官瞅瞅就好,大神還希望多多指正。此篇文章總結(jié)與《JavaScript忍者秘籍》 《你不知道的JavaScri...
摘要:使用上一篇文章的例子來說明下自由變量進階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數(shù),也不是局部變量,所以是自由變量。 (關(guān)注福利,關(guān)注本公眾號回復[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實戰(zhàn)、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第7天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計...
摘要:說了半天,究竟什么是閉包呢閉包就是函數(shù)的局部變量集合,只是這些局部變量在函數(shù)返回后會繼續(xù)存在。彈出上面函數(shù)中的函數(shù)就是閉包,就是通過建立函數(shù)來訪問函數(shù)內(nèi)部的局部變量。閉包會在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值。 JavaScript的閉包 首先聲明,這是一篇面向小白的博客,不過也歡迎各位大牛批評指正,謝謝。 ??其實關(guān)于閉包各個論壇社區(qū)里都有很多的文章來講它,畢竟閉包是JavaScri...
閱讀 3204·2021-10-14 09:42
閱讀 3572·2019-08-26 13:56
閱讀 3482·2019-08-26 11:59
閱讀 948·2019-08-23 18:00
閱讀 2213·2019-08-23 17:51
閱讀 3534·2019-08-23 17:17
閱讀 1487·2019-08-23 15:11
閱讀 5203·2019-08-23 15:05