摘要:在一個(gè)閉包環(huán)境內(nèi)修改變量值,不會(huì)影響另一個(gè)閉包中的變量。直到看到函數(shù)閉包閉包這篇文章的代碼一部分,終于明白其中的邏輯了。
閉包
閉包定義:指擁有多個(gè)變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個(gè)函數(shù)),因而這些變量也是該表達(dá)式的一部分。
函數(shù)內(nèi)部可以直接讀取全局變量。
函數(shù)內(nèi)部變量無(wú)法在函數(shù)外部訪問(wèn)。
函數(shù)內(nèi)部聲明要用var或者let聲明,不然會(huì)變成全局變量
鏈?zhǔn)阶饔糜颍鹤訉?duì)象會(huì)一級(jí)級(jí)向上尋找父對(duì)象的變量,父對(duì)象的變量子對(duì)象都是可見(jiàn)的,反之則不行。
在一個(gè)閉包環(huán)境內(nèi)修改變量值,不會(huì)影響另一個(gè)閉包中的變量。
普通的函數(shù)內(nèi)嵌,內(nèi)部函數(shù)是先執(zhí)行;而閉包則是:先把內(nèi)部函數(shù)賦給外部函數(shù),然后在執(zhí)行。
下面這段代碼就是一根典型的閉包
function f1(){ var a = 10; function f2(){ alert(a); } f2(); //① } f1(); //10 ②
f1和f1()的區(qū)別不加括號(hào)是代碼,加()是執(zhí)行這段代碼,加return是返回一個(gè)值,可以把返回的值賦值給變量,不加return默認(rèn)返回undefined;
所以①處有三種寫(xiě)法:
第一種:①處寫(xiě)f2();,②處調(diào)用需要這樣寫(xiě)f1();。具體執(zhí)行過(guò)程:f1體內(nèi)調(diào)用f2函數(shù),并執(zhí)行。
第二種:①處寫(xiě)return f2();,②處調(diào)用需這樣寫(xiě)f1();。具體執(zhí)行過(guò)程:同上;區(qū)別是多了個(gè)return,因?yàn)楝F(xiàn)在f2函數(shù)中沒(méi)有返回值,所以f1在調(diào)用f2只是執(zhí)行一下alert(a),f1的返回值是undefined。
第三種:①處寫(xiě)return f2;,②處調(diào)用需這樣寫(xiě)f1()();。這里返回的是f2函數(shù)的代碼,所以在調(diào)用f1時(shí)要加上2個(gè)括號(hào),第一個(gè)括號(hào)是執(zhí)行f1函數(shù),第2個(gè)括號(hào)是執(zhí)行f2函數(shù),如果①處省略return會(huì)報(bào)錯(cuò)。
return和函數(shù)調(diào)用時(shí)是否加括號(hào)的意思都明白,但是把它倆結(jié)合起來(lái),就搞不清了。
正好今天學(xué)閉包時(shí)碰上了,順便就把它搞清楚了。
到底什么是閉包對(duì)于新人(當(dāng)然了是說(shuō)我了),看很多閉包的定義,代碼,還是不知啥是閉包,云里霧里的,這里感謝方方老師的文章JS 中的閉包是什么?,看完后,雖然還是說(shuō)不出啥是閉包,但現(xiàn)在已經(jīng)知道啥是閉包了,果然用圖說(shuō)話(huà)最牛逼。(圖在文章中,我就不放出來(lái)了)
閉包的應(yīng)用MDN 上這個(gè)例子也寫(xiě)的很好
調(diào)用Counter.value()時(shí),返回的是Counter內(nèi)部的變量privateCounter;
increment內(nèi)部沒(méi)有返回值,這個(gè)方法只是執(zhí)行了privateCounter + 1操作,沒(méi)有返回值;
同理decrement是將privateCounter - 1,也沒(méi)有返回值;
所以執(zhí)行Counter.increment,會(huì)返回undefined,但是接著操作Counter.value()時(shí)就可以得到1,因?yàn)閳?zhí)行上一步Counter.increment時(shí)privateCounter被+1了。
今天在下面三段代碼上花費(fèi)了大量的時(shí)間,一直似懂非懂,心里不踏實(shí)。
代碼一:
var name = "window"; var obj = { name: "object", getName: function() { return this.name; } }; obj.getName(); //object (obj.getName = obj.getName)(); //window 非嚴(yán)格模式下
代碼二:
var name = "window"; var obj = { name: "object", getName: function() { return function(){ return this.name; } } }; obj.getName()(); //window
代碼三:
var name = "window"; var obj = { name : "object", getName : function(){ var that = this; return function(){ return that.name; }; } }; obj.getName()(); //object
今天在看阮一峰的博客學(xué)習(xí)Javascript閉包(Closure),對(duì)代碼二、代碼三部分很是不解,看到一網(wǎng)友搬出犀牛書(shū)(還沒(méi)看過(guò),我買(mǎi)了紅寶石書(shū)才看了一點(diǎn)點(diǎn))里的話(huà),實(shí)在不解什么是作為函數(shù)調(diào)用,什么是作為方法調(diào)用;
《Javascript權(quán)威指南》上說(shuō):如果嵌套函數(shù)作為函數(shù)調(diào)用,其this值不是全局對(duì)象(非嚴(yán)格模式下)就是undefined(嚴(yán)格模式下); 如果嵌套函數(shù)作為方法調(diào)用,其this值指向調(diào)用它的對(duì)象。
又有一位網(wǎng)友說(shuō)
每個(gè)函數(shù)在被調(diào)用時(shí),其活動(dòng)對(duì)象都會(huì)自動(dòng)取得兩個(gè)特殊變量:this和arguments。內(nèi)部函數(shù)在搜索這個(gè)變量時(shí),只會(huì)搜索到其活動(dòng)對(duì)象為止,因此永遠(yuǎn)不可能直接訪問(wèn)外部函數(shù)中的這兩個(gè)變量(這一點(diǎn)通過(guò)前面的圖可以看得更清楚)。意思就是說(shuō)找到匿名函數(shù)中的this和arguments就不會(huì)再往下找了(這里的往下指的是外層的包含函數(shù),和最外層的window全局環(huán)境),而匿名函數(shù)的this對(duì)象通常指向window,所以輸出的是全局的那個(gè)字符串。不過(guò),把外部作用域中的this對(duì)象保存在一個(gè)閉包能夠訪問(wèn)到的變量里,就可以讓閉包訪問(wèn)該對(duì)象了。
看到這里大概明白匿名函數(shù)的作用域是全局,繼續(xù)翻看下面評(píng)論,大概意思是說(shuō)“把this保存在obj作用域下的一個(gè)變量中,this就在當(dāng)前函數(shù)的作用域下了”。直到看完也是,似懂非懂,反正就是感覺(jué)哪里不對(duì)勁,但也說(shuō)不上了。
直到看到【JavaScript】【函數(shù)】閉包閉包!這篇文章的代碼一部分,終于明白其中的邏輯了。
下面就來(lái)分析其中的邏輯,我分析的方法就是把不懂的地方一個(gè)個(gè)用console打印出來(lái)
代碼二和代碼一的區(qū)別是多了一層嵌套函數(shù),this值就不一樣了。
ps:我一開(kāi)始以為在代碼二中再嵌套一層函數(shù),就會(huì)打印出object =_=|||
先來(lái)看代碼一,明白之后,另外兩段代碼自然就懂了。
為什么obj.getName()打印出來(lái)的是object,因?yàn)檫@時(shí)getName方法是在obj的作用域下,所以this指向obj,返回值當(dāng)然就是object了。
接著看(obj.getName = obj.getName)()刪掉右邊后,打印出的結(jié)果變成了object,這就納悶了。
ps:第一眼看上去,這啥玩意,把自己賦值給自己?這不是多此一舉,直接用不就行了!
用console.log打印出obj.getName后,終于撥云見(jiàn)天,obj.getName = obj.getName這句話(huà)的意思就是把getName函數(shù)賦值給自己,這個(gè)時(shí)候就不是obj.getName,而是getName匿名函數(shù)了,匿名函數(shù)通常用的方法是()()立即執(zhí)行,此時(shí)再看匿名函數(shù)已經(jīng)脫離obj了,當(dāng)然this也就指向了全局,打印出window。
再來(lái)看代碼二,用console打印出obj.getName()會(huì)發(fā)現(xiàn)是一個(gè)匿名函數(shù),而匿名函數(shù)的this通常會(huì)指向全局,所以也就不難理解了
理解上面兩段代碼,代碼三也就很好理解了。
閉包中引用循環(huán)變量廖雪峰的閉包在文中就很形象的講解了函數(shù)中的引用會(huì)變化的變量會(huì)有什么后果,我節(jié)選了他的結(jié)論和代碼。
返回閉包時(shí)牢記的一點(diǎn)就是:返回函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會(huì)發(fā)生變化的變量。
如果一定要引用循環(huán)變量怎么辦?方法是再創(chuàng)建一個(gè)函數(shù),用該函數(shù)的參數(shù)綁定循環(huán)變量當(dāng)前的值,無(wú)論該循環(huán)變量后續(xù)如何更改,已綁定到函數(shù)參數(shù)的值不變:
function count() { var arr = []; for (var i=1; i<=3; i++) { arr.push((function (n) { return function () { return n * n; } })(i)); } return arr; } var results = count(); var f1 = results[0]; var f2 = results[1]; var f3 = results[2]; f1(); // 1 f2(); // 4 f3(); // 9
這里的核心就是立即執(zhí)行,如果不是立即執(zhí)行的話(huà),變量i就是for循環(huán)結(jié)束后的值了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/95041.html
摘要:本筆記共四篇源碼閱讀筆記源碼閱讀筆記源碼閱讀筆記服務(wù)器啟動(dòng)與請(qǐng)求處理源碼閱讀筆記對(duì)象起因前兩天終于把自己一直想讀的源代碼讀了一遍。首先放上關(guān)鍵的源代碼在上一篇源碼閱讀筆記服務(wù)器啟動(dòng)與請(qǐng)求處理中,我們已經(jīng)分析了的作用。 本筆記共四篇Koa源碼閱讀筆記(1) -- coKoa源碼閱讀筆記(2) -- composeKoa源碼閱讀筆記(3) -- 服務(wù)器の啟動(dòng)與請(qǐng)求處理Koa源碼閱讀筆記(4...
摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。異步編程入門(mén)的全稱(chēng)是前端經(jīng)典面試題從輸入到頁(yè)面加載發(fā)生了什么這是一篇開(kāi)發(fā)的科普類(lèi)文章,涉及到優(yōu)化等多個(gè)方面。 TypeScript 入門(mén)教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識(shí)之 HTTP 協(xié)議 詳細(xì)介紹 HTT...
摘要:最近看前端都展開(kāi)了幾場(chǎng)而我大知乎最熱語(yǔ)言還沒(méi)有相關(guān)。有關(guān)書(shū)籍的介紹,大部分截取自是官方介紹。但從開(kāi)始,標(biāo)準(zhǔn)庫(kù)為我們提供了模塊,它提供了和兩個(gè)類(lèi),實(shí)現(xiàn)了對(duì)和的進(jìn)一步抽象,對(duì)編寫(xiě)線程池進(jìn)程池提供了直接的支持。 《流暢的python》閱讀筆記 《流暢的python》是一本適合python進(jìn)階的書(shū), 里面介紹的基本都是高級(jí)的python用法. 對(duì)于初學(xué)python的人來(lái)說(shuō), 基礎(chǔ)大概也就夠用了...
摘要:原文地址一個(gè)非常適合入門(mén)學(xué)習(xí)的博客項(xiàng)目前端掘金一個(gè)非常適合入門(mén)學(xué)習(xí)的項(xiàng)目,代碼清晰結(jié)構(gòu)合理新聞前端掘金介紹一個(gè)由編寫(xiě)的新聞。深入淺出讀書(shū)筆記知乎專(zhuān)欄前端專(zhuān)欄前端掘金去年的一篇老文章,恰好今天專(zhuān)欄開(kāi)通,遷移過(guò)來(lái)。 破解前端面試(80% 應(yīng)聘者不及格系列):從閉包說(shuō)起 - 掘金修訂說(shuō)明:發(fā)布《80% 應(yīng)聘者都不及格的 JS 面試題》之后,全網(wǎng)閱讀量超過(guò) 6W,在知乎、掘金、cnodejs ...
摘要:原文地址一個(gè)非常適合入門(mén)學(xué)習(xí)的博客項(xiàng)目前端掘金一個(gè)非常適合入門(mén)學(xué)習(xí)的項(xiàng)目,代碼清晰結(jié)構(gòu)合理新聞前端掘金介紹一個(gè)由編寫(xiě)的新聞。深入淺出讀書(shū)筆記知乎專(zhuān)欄前端專(zhuān)欄前端掘金去年的一篇老文章,恰好今天專(zhuān)欄開(kāi)通,遷移過(guò)來(lái)。 破解前端面試(80% 應(yīng)聘者不及格系列):從閉包說(shuō)起 - 掘金修訂說(shuō)明:發(fā)布《80% 應(yīng)聘者都不及格的 JS 面試題》之后,全網(wǎng)閱讀量超過(guò) 6W,在知乎、掘金、cnodejs ...
閱讀 1207·2021-09-03 10:44
閱讀 603·2019-08-30 13:13
閱讀 2796·2019-08-30 13:11
閱讀 1967·2019-08-30 12:59
閱讀 1034·2019-08-29 15:32
閱讀 1595·2019-08-29 15:25
閱讀 987·2019-08-29 12:24
閱讀 1277·2019-08-27 10:58