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