摘要:在中,閉包其實(shí)隨處可見。但真要說起什么是閉包的話,很多人可能一時(shí)半會(huì)不知道怎么解釋。這篇博文主要寫一些閉包的特性已經(jīng)相關(guān)的應(yīng)用。
在JavaScript中,閉包其實(shí)隨處可見。但真要說起什么是閉包的話,很多人可能一時(shí)半會(huì)不知道怎么解釋。這篇博文主要寫一些閉包的特性已經(jīng)相關(guān)的應(yīng)用。定義
參考資料:阮一峰——JavaScript運(yùn)行機(jī)制詳解
閉包是指在函數(shù)聲明時(shí)的作用域以外的地方被調(diào)用的函數(shù),在函數(shù)聲明時(shí)的作用域以外的地方調(diào)用函數(shù),需要通過將該函數(shù)作為返回值或者作為參數(shù)被傳遞
特性光看定義的話可能會(huì)比較懵逼(╯‵□′)╯︵┻━┻ 下面來看一下閉包到底都有哪些特性:
函數(shù)在自己定義的詞法作用域以外的地方執(zhí)行
函數(shù)嵌套
訪問所在的詞法作用域
循環(huán)閉包 定義在循環(huán)中包含了函數(shù)定義則稱為循環(huán)閉包
實(shí)例1講了這么多,下面來看一段例子:
for(var i = 1; i < 6; i++){ setTimeout(function(){ console.log(i); },50); } //輸出結(jié)果為: 6 6 6 6 6
好吧,如果你是新手的話,看到這里你是震驚的,因?yàn)樽鳛橐粋€(gè)萌新,當(dāng)初我對(duì)這串代碼的想法是這樣的:
setTimeout函數(shù)在for循環(huán)中執(zhí)行六次,每隔50ms輸出一個(gè)數(shù)字,則會(huì)分別輸出1、2、3、4、5
后來我發(fā)現(xiàn),用關(guān)鍵字var聲明的變量會(huì)存在變量提升的情況,循環(huán)結(jié)束以后,變量i不會(huì)被JavaScript引擎的垃圾回收機(jī)制回收,而是成為全局變量。
所以我的的初步解釋為:
由關(guān)鍵字var聲明的變量存在變量提升的情況,循環(huán)結(jié)束以后變量i變?yōu)槿肿兞?/p>
for循環(huán)結(jié)束的比50ms要早,所以setTimeout函數(shù)讀取不到迭代的變量i,而是循環(huán)結(jié)束后的變量i
實(shí)例2然而上面只是我一開始錯(cuò)誤的認(rèn)識(shí),直到我看到下面的代碼:
for(var i=1;i<6;i++){ setTimeout(function(){ console.log(i); },0); } //輸出結(jié)果為: 6 6 6 6 6
因?yàn)檫@里setTimeout的時(shí)間參數(shù)是0,如果照著上面的思路來的話,這里的輸出應(yīng)該是 1 2 3 4 5
JavaScript調(diào)用機(jī)制在講述解決方法之前我們先來了解一下JavaScript的調(diào)用機(jī)制
對(duì)JavaScript比較熟悉的人應(yīng)該了解,JavaScript是一種單線程的語言。而我們?cè)诰帉懘a的時(shí)候,往往不止同步的代碼,還有異步執(zhí)行的代碼,JavaScript這里把它分成兩種模式,一種叫做同步任務(wù),另一種則叫做異步任務(wù)。在執(zhí)行代碼的時(shí)候,同步任務(wù)被分配在主線程中執(zhí)行,形成一個(gè)調(diào)用棧;而異步任務(wù)則交給瀏覽器的其他線程去執(zhí)行。當(dāng)異步任務(wù)執(zhí)行完畢以后,則將對(duì)應(yīng)的異步任務(wù)放入任務(wù)隊(duì)列中。當(dāng)調(diào)用棧中的任務(wù)都執(zhí)行完畢以后,再讀取任務(wù)隊(duì)列,取消對(duì)應(yīng)任務(wù)的等待狀態(tài),然后進(jìn)入調(diào)用棧,開始執(zhí)行。解決方法
方法1:綁定作用域,將關(guān)鍵字var改為let,具體代碼為:
for(let i=1;i<6;i++){ setTimeout(function(){ console.log(i) },50) }
方法2:運(yùn)用IIFE(立即執(zhí)行函數(shù)),具體代碼為:
for(var i=1;i<6;i++){ (function(j){ setTimeout(function(){ console.log(j) },50) })(i); }
在迭代內(nèi)部使用IIFE會(huì)為每個(gè)迭代生成一個(gè)新的作用域,使得延遲函數(shù)的回調(diào)可以將新的作用域封閉在每個(gè)迭代內(nèi)部,每個(gè)迭代都含有一個(gè)具有正確值的變量供我們?cè)L問
總結(jié)閉包在JavaScript里隨處可見,我們?cè)谑褂瞄]包的時(shí)候,需要謹(jǐn)慎的在循環(huán)內(nèi)部添加閉包。個(gè)人覺得最好的解決方案就是使用關(guān)鍵字let,可讀性強(qiáng)而且另代碼整潔,希望ES6能夠全面普及。
掃描下方的二維碼或搜索「tony老師的前端補(bǔ)習(xí)班」關(guān)注我的微信公眾號(hào),那么就可以第一時(shí)間收到我的最新文章。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/85016.html
摘要:大名鼎鼎的閉包面試必問。閉包的作用是什么??吹介]包在哪了嗎閉包到底是什么五年前,我也被這個(gè)問題困擾,于是去搜了并總結(jié)下來。關(guān)于閉包的謠言閉包會(huì)造成內(nèi)存泄露錯(cuò)。閉包里面的變量明明就是我們需要的變量,憑什么說是內(nèi)存泄露這個(gè)謠言是如何來的因?yàn)椤? 本文為饑人谷講師方方原創(chuàng)文章,首發(fā)于 前端學(xué)習(xí)指南。 大名鼎鼎的閉包!面試必問。請(qǐng)用自己的話簡(jiǎn)述 什么是「閉包」。 「閉包」的作用是什么。 首先...
摘要:完美的閉包,對(duì),閉包就這么簡(jiǎn)單。這僅僅是閉包的一部分,閉包利用函數(shù)作用域達(dá)到了訪問外層變量的目的。此時(shí)一個(gè)完整的閉包實(shí)現(xiàn)了,的垃圾回收機(jī)制由于閉包的存在無法銷毀變量。 1.閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)。 上面這段話來自 javascript 高級(jí)程序設(shè)計(jì) 第三版 P178 。作者說閉包是一個(gè)函數(shù),它有訪問另一個(gè)函數(shù)作用域中的變量的能力。 2.函數(shù)訪問它被創(chuàng)建時(shí)所處的...
摘要:第二梯隊(duì)理解有了第一梯隊(duì)的認(rèn)識(shí),我們慢慢修正大腦中對(duì)閉包的認(rèn)識(shí)。理解這句話就可以很好的與閉包這兩個(gè)字關(guān)聯(lián)起來理解閉包這個(gè)概念了??偨Y(jié)第二梯隊(duì)理解閉包是一個(gè)有特定功能的函數(shù)。第四梯隊(duì)理解閉包通過訪問外部變量,一個(gè)閉包可以維持這些變量。 閉包 閉包的概念困惑了我很久,記得當(dāng)時(shí)我面試的時(shí)候最后一面有一個(gè)問題就是問題關(guān)于閉包的問題,然而到現(xiàn)在已經(jīng)完全不記得當(dāng)時(shí)的題目是啥了,但仍然能夠回憶起當(dāng)時(shí)...
摘要:到底什么是閉包這個(gè)問題在面試是時(shí)候經(jīng)常都會(huì)被問,很多小白一聽就懵逼了,不知道如何回答好。上面這么說閉包是一種特殊的對(duì)象。閉包的注意事項(xiàng)通常,函數(shù)的作用域及其所有變量都會(huì)在函數(shù)執(zhí)行結(jié)束后被銷毀。從而使用閉包模塊化代碼,減少全局變量的污染。 閉包,有人說它是一種設(shè)計(jì)理念,有人說所有的函數(shù)都是閉包。到底什么是閉包?這個(gè)問題在面試是時(shí)候經(jīng)常都會(huì)被問,很多小白一聽就懵逼了,不知道如何回答好。這個(gè)...
閱讀 1957·2021-11-15 17:58
閱讀 2136·2021-10-19 11:45
閱讀 3502·2021-09-02 15:40
閱讀 2604·2021-07-25 10:50
閱讀 3752·2019-08-30 15:56
閱讀 3153·2019-08-30 12:44
閱讀 1035·2019-08-26 13:38
閱讀 1878·2019-08-23 18:29