摘要:每次循環(huán)都會(huì)創(chuàng)建一個(gè)以立即執(zhí)行函數(shù)為作用域的變量,原來(lái)在程序中函數(shù)訪(fǎng)問(wèn)的是外部變量,現(xiàn)在訪(fǎng)問(wèn)的是這一閉包中的變量。
這是篇文章主要是講一下對(duì)閉包這一概念的理解。討論閉包之前,我們先從一個(gè)經(jīng)典的例子說(shuō)起
// 程序1 var arr = [] for(var i = 0; i < 3; i++){ arr[i] = function () { console.log(i) } } arr[0]() // 3 arr[1]() // 3 arr[2]() // 3
大家都知道,這段代碼最終輸出都為3。因?yàn)楹瘮?shù)調(diào)用的時(shí)候循環(huán)已經(jīng)結(jié)束了所以 i 等于3,更為重要的是,es6之前沒(méi)有塊作用域,變量 i 的作用域不在for循環(huán)中,而在for循環(huán)之外。如果我們想要看到輸出結(jié)果依次為0,1,2,就得用到閉包了。否則,除非我們能在每次循環(huán)的過(guò)程中調(diào)用函數(shù),因?yàn)橹挥性谘h(huán)進(jìn)行的過(guò)程中 i 才會(huì)處于0,1,2的狀態(tài)。比如像這樣:
// 程序2 for(var i = 0; i < 3; i++){ (function () { console.log(i) })() } // 0 // 1 // 2
必須要在循環(huán)進(jìn)行時(shí)調(diào)用哦,像下面這樣都不行!
// 程序3 for(var i = 0; i < 3; i++){ setTimeout(function () { console.log(i) }, 0) } // 3 // 3 // 3
當(dāng)然程序2這樣寫(xiě)已經(jīng)失去意義了,這個(gè)程序的目的就是要給數(shù)組加幾個(gè)函數(shù)供以后調(diào)用,而不是馬上就要調(diào)用它。閉包主要就是用來(lái)解決這樣的問(wèn)題,它讓函數(shù)可以訪(fǎng)問(wèn)到函數(shù)所被創(chuàng)建時(shí)的上下文環(huán)境,不論這個(gè)函數(shù)在什么時(shí)候被調(diào)用。所以閉包產(chǎn)生的條件有兩個(gè),一是函數(shù)能通過(guò)變量作用域規(guī)則訪(fǎng)問(wèn)到它被創(chuàng)建時(shí)的上下文環(huán)境,例如程序1,函數(shù)只是簡(jiǎn)單的訪(fǎng)問(wèn)了外部的變量 i,嚴(yán)格上講不算閉包。二是函數(shù)在其它地方執(zhí)行時(shí),函數(shù)依然能夠記住并訪(fǎng)問(wèn)到它所被定義時(shí)的上下文環(huán)境,我們使用閉包來(lái)對(duì)程序1進(jìn)行修改:
// 程序4 var arr = [] for(var i = 0; i < 3; i++){ (function () { var j = i arr[i] = function () { console.log(j) } })() } arr[0]() // 0 arr[1]() // 1 arr[2]() // 2
不同的是這次增加了立即執(zhí)行函數(shù)并在里面定義變量 j ,我們可以把立即執(zhí)行函數(shù)稱(chēng)為 fn 。每次循環(huán)都會(huì)創(chuàng)建一個(gè)以立即執(zhí)行函數(shù)為作用域的變量 j ,原來(lái)在程序1中函數(shù)訪(fǎng)問(wèn)的是外部變量 i ,現(xiàn)在訪(fǎng)問(wèn)的是fn這一閉包中的變量 j 。fn執(zhí)行結(jié)束時(shí) j 本應(yīng)被回收,但是由于該作用域內(nèi)還定義了一個(gè)內(nèi)部訪(fǎng)問(wèn)了變量 j 的函數(shù),該函數(shù)在未來(lái)可能被執(zhí)行,所以 j 被“記住”了,也就是作用域鏈被保存了。我們可以把fn稱(chēng)為一個(gè)閉包,閉包內(nèi)可以定義函數(shù)并且這些函數(shù)可以訪(fǎng)問(wèn)閉包中定義的變量,例如:
function fn(){ var a = 1; return function(){ console.log(a) } } var module = fn() module() // 1
fn返回的函數(shù)通過(guò)閉包能夠訪(fǎng)問(wèn)到 a。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/105628.html
摘要:回憶我一年前,雖然使用過(guò)很多,但卻完全不理解閉包是什么。就算你,也會(huì)在循環(huán)完成時(shí),輸出次當(dāng)然,不要以為主要的原因是延遲函數(shù)會(huì)在循環(huán)結(jié)束時(shí)才執(zhí)行,不然我為什么會(huì)在閉包這一節(jié)用使用這個(gè)例子,哈哈。 前言 在了解閉包的概念時(shí),我希望你能夠有JavaScript詞法作用域的知識(shí),因?yàn)樗鼤?huì)讓你更容易讀懂這篇文章。 感觸 對(duì)于那些使用過(guò)JavaScript但卻完全不理解閉包概念的人來(lái)說(shuō),理解閉包可...
摘要:由于匿名函數(shù)的作用域是全局性的,因此閉包的通常指向全局對(duì)象調(diào)用返回值為而不是我們預(yù)期的,在閉包中函數(shù)作為某個(gè)對(duì)象的方法調(diào)用時(shí),要特別注意,該方法內(nèi)部匿名函數(shù)的指向的是全局變量。 有人的地方就有江湖,有函數(shù)的地方就有this。而this在不同的環(huán)境下,又表現(xiàn)為不同的形式,難免讓人有種此this非彼this的疑惑 在java等面向?qū)ο蟮恼Z(yǔ)言中,this指的就是當(dāng)前對(duì)象,而在jav...
摘要:詞法作用域的查找規(guī)則是閉包的一部分。因此的確同閉包息息相關(guān),即使本身并不會(huì)真的使用閉包。而上面的創(chuàng)建一個(gè)閉包,本質(zhì)上這是將一個(gè)塊轉(zhuǎn)換成一個(gè)可以被關(guān)閉的作用域。結(jié)合塊級(jí)作用域與閉包模塊這個(gè)模式在中被稱(chēng)為模塊。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門(mén)充滿(mǎn)吸引力、簡(jiǎn)單易用的語(yǔ)言,又是一門(mén)具有許多復(fù)雜微妙技術(shù)的語(yǔ)言,即使是經(jīng)驗(yàn)豐富的 Jav...
閉包,顧名思義就是一個(gè)封閉的包裹,你沒(méi)辦法窺探到其內(nèi)部,只能通過(guò)暴露給你的方法進(jìn)行操作。其實(shí)在寫(xiě)代碼的過(guò)程中,我們可能已經(jīng)使用了閉包,只是當(dāng)時(shí)不知道而已。等理解了閉包,再去回顧以前的代碼,就會(huì)發(fā)現(xiàn)JavaScript中閉包無(wú)處不在。剛開(kāi)始學(xué)習(xí)閉包的時(shí)候,我看過(guò)很多關(guān)于閉包的文章,大部分都會(huì)舉例這樣一段代碼:showImg(https://segmentfault.com/img/bVO3Mo?w=...
摘要:函數(shù)在執(zhí)行的時(shí)候執(zhí)行函數(shù),將當(dāng)前的變量對(duì)象由于當(dāng)前的環(huán)境是函數(shù),所以將其活動(dòng)對(duì)象作為變量對(duì)象添加到作用域鏈的前端。此時(shí),由于在執(zhí)行,而作用域鏈也存在,所以可以在作用域鏈上進(jìn)行查找,去訪(fǎng)問(wèn)的變量。 一、現(xiàn)狀 閉包是jser繞不過(guò)的坎,一直在都在說(shuō),套用 simpson 的話(huà)來(lái)說(shuō):JavaScript中閉包無(wú)處不在,你只需要能夠識(shí)別并擁抱它。 閉包是基于詞法作用域書(shū)寫(xiě)代碼時(shí)的自然結(jié)果,你甚...
閱讀 1908·2021-11-25 09:43
閱讀 1556·2021-09-02 15:21
閱讀 3522·2019-08-30 15:52
閱讀 1556·2019-08-30 12:48
閱讀 1372·2019-08-30 10:57
閱讀 2988·2019-08-26 17:41
閱讀 741·2019-08-26 11:59
閱讀 1425·2019-08-26 10:41