摘要:而閉包卻能阻止這件事情發(fā)生。由于的聲明位置使它擁有涵蓋內(nèi)部作用域的閉包,使得該作用域能夠一直存在,以供在之后進行引用。到這里,小菊花課堂之閉包的內(nèi)容就告一段落啦,感謝各位能耐心看到這里。
由于前段時間項目沒有那么忙,然后我這人一天不看點啥就非常焦慮,于是二刷《你不知道的JavaScript》,現(xiàn)在讀到閉包,想著看完這一章節(jié),寫點東西也是挺好的,所以有了下面的內(nèi)容,如有不對的地方,敬請斧正,歡迎探討。
作用域我們一般講到閉包,就會談到作用域,那么作用域又分為了函數(shù)作用域和塊級作用域 ,在這里,我們簡單的介紹一下這兩種作用域。
函數(shù)作用域函數(shù)作用域是指,屬于這個函數(shù)的全部變量都可以在整個函數(shù)的范圍內(nèi)使用及服用(事實上在嵌套的作用域中也可以使用)。
我們先來看一個例子
var a = 2; function foo() { var a = 3; console.log(a); // 3 } foo(); console.log(a); // 2
可以看到,這種技術(shù)雖然能解決一些問題,但是也會導(dǎo)致其他的問題。首先,必須聲明一個具名函數(shù)foo(),意味著foo這個名稱本身“污染”了所在的作用域。其次,必須顯式地(有隱式和顯式的區(qū)別,這里暫且不表)通過函數(shù)名(foo())調(diào)用這個函數(shù)才能運行其中的代碼。
那么我們有沒有其他的辦法呢,繼續(xù)往下看。
var a = 2 (function foo() { var a = 3; console.log(a); // 3 })(); console.log(a); // 2
比較一下這兩段代碼。第一段中foo被綁定在所在所用域中,可以直接通過foo()來調(diào)用調(diào)用它。第二段中foo被綁定在函數(shù)表達式自身的函數(shù)中而不是所在作用域中。
塊級作用域在JavaScript中,并不支持塊作用域,但是我們?yōu)槭裁催€要說它,因為它的風(fēng)格在JS開發(fā)中很常見。
在日常的開發(fā)或者學(xué)習(xí)工作中,我們其實經(jīng)常能見到類似塊作用域,思考以下代碼:
for(var i=0; i<6; i++){ console.log(i); }
在for循環(huán)的頭部直接定義了變量 i,通常是因為只想在for循環(huán)內(nèi)部的上下文中使用 i,而忽略了 i 會被綁定在外部作用域(函數(shù)或全局)中的事實。當(dāng)使用var時,它寫在哪里都是一樣的,因為它們最終都會屬于外部作用域。
塊作用域是一個用來對之前的最小授權(quán)原則進行擴展的工具,將代碼從在函數(shù)中隱藏信息擴展為在塊中隱藏信息。
繼續(xù)思考下面代碼:
function foo() { var a = 2; function bar() { console.log(a); } return bar; } var baz = foo(); baz(); // 2
看到了嗎,這就是閉包的效果。
函數(shù)bar()的詞法作用域能夠訪問foo()的內(nèi)部作用域。然后將bar()函數(shù)本身當(dāng)作一個值類型進行傳遞。
在foo()執(zhí)行后,其返回值賦值給變量baz并調(diào)用baz(),實際上只是通過不同的標(biāo)識符引用調(diào)用了內(nèi)部的函數(shù)bar()。
我們知道,JavaScript引擎有垃圾回收器用來釋放不再使用的內(nèi)存空間。而閉包卻能阻止這件事情發(fā)生。事實上內(nèi)部作用域依然存在,而沒有被回收。
由于bar()的聲明位置使它擁有涵蓋foo()內(nèi)部作用域的閉包,使得該作用域能夠一直存在,以供bar()在之后進行引用。
再看下面例子
function foo() { var a = 2; function baz() { console.log(a); // 2 } bar(baz); } function bar(fn) { fn(); // 這是閉包 } foo();
無論通過何種手段將內(nèi)部函數(shù)傳遞到所在的詞法作用域外,它都會持有對原始定義作用域的引用,無論在何處執(zhí)行這個函數(shù)都會使用閉包。
OK,本質(zhì)上無論何時何地,如果將(訪問它們各自詞法作用域的)函數(shù)當(dāng)作第一級的值類型并到處傳遞,你就能看到閉包了。在定時器、事件監(jiān)聽器、Ajax請求或其他異步或同步任務(wù)中,只要使用了回調(diào)函數(shù),實際上就是在使用閉包。
循環(huán)與閉包先看看最常見的for循環(huán)。
for(var i=1; i<=5; i++) { setTimeout(function timer(){ console.log(i); }, i*1000) }
你覺得最后會輸出什么,每秒輸出一次,分別輸出1~5?
那就錯啦,實際上,它是會每秒輸出一次,但輸出~對,就是66666。
為什么?
延遲函數(shù)的回調(diào)會在循環(huán)結(jié)束時才執(zhí)行,而循環(huán)結(jié)束的條件就是i不再<=5。當(dāng)定時器運行時,即使每個迭代中執(zhí)行的是setTimeout(...,0),所有的回調(diào)函數(shù)依然是在循環(huán)結(jié)束后才被執(zhí)行,所以每次都輸出6。
根據(jù)作用域的原理,盡管循環(huán)中的五個函數(shù)是在各個迭代中分別定義的,但是它們都被封閉在一個共享的全局作用域中,因此只有一個i。
知道原因之后,我們可以對代碼進行一些改造,看看有沒有好事發(fā)生。
foo(var i=1; i<=5; i++) { (function (j) { setTimeout(function timer() { console.log(j); }, j*1000); })(i); }
Fine,我們終于改造好了,擁有了更多的詞法作用域。在迭代中使用立即執(zhí)行函數(shù)(IIFE)會為每個迭代都生成一個新的作用域,使得延遲函數(shù)的回調(diào)可以將新的作用域封閉在每個迭代內(nèi)部,每個迭代中都會有一個具有正確值的變量。
到這里,小菊花課堂之JavaScript閉包的內(nèi)容就告一段落啦,感謝各位能耐心看到這里。
此時是0點52分,時候也不早了,該洗洗睡啦。
see u ~ again
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/98801.html
摘要:另外,的綁定和函數(shù)聲明的位置沒有任何關(guān)系,之取決于函數(shù)的調(diào)用方式。請看下面代碼這樣,我們就可以在調(diào)用的時候強制把它的綁定到上綁定在傳統(tǒng)的面向類語言中,使用初始化類時會調(diào)用類中的構(gòu)造函數(shù)。 關(guān)于this 上一章我們講了關(guān)于作用域和閉包的相關(guān)知識,現(xiàn)在開始新一輪的學(xué)習(xí),那就是JavaScript中最復(fù)雜的機制之一---this關(guān)鍵字。它是一個很特別的關(guān)鍵字,被自動定義在所有函數(shù)的作用域中。...
摘要:文章來源詳談防抖和節(jié)流輕松理解函數(shù)節(jié)流和函數(shù)防抖函數(shù)防抖和節(jié)流好啦,今天的小菊花課堂之的防抖與節(jié)流的內(nèi)容就告一段落啦,感各位能耐心看到這里。 前言 陸游有一首《冬夜讀書示子聿》——古人學(xué)問無遺力,少壯工夫老始成。紙上得來終覺淺,絕知此事要躬行。,其中的意思想必大家都能明白,在學(xué)習(xí)或工作中,不斷的印證著這首詩的內(nèi)涵。所以,又有了此篇小菊花文章。 詳解 在前端開發(fā)中,我們經(jīng)常會碰到一些會持...
摘要:文章來源詳談防抖和節(jié)流輕松理解函數(shù)節(jié)流和函數(shù)防抖函數(shù)防抖和節(jié)流好啦,今天的小菊花課堂之的防抖與節(jié)流的內(nèi)容就告一段落啦,感各位能耐心看到這里。 前言 陸游有一首《冬夜讀書示子聿》——古人學(xué)問無遺力,少壯工夫老始成。紙上得來終覺淺,絕知此事要躬行。,其中的意思想必大家都能明白,在學(xué)習(xí)或工作中,不斷的印證著這首詩的內(nèi)涵。所以,又有了此篇小菊花文章。 詳解 在前端開發(fā)中,我們經(jīng)常會碰到一些會持...
摘要:的變量作用域是基于其特有的作用域鏈的。需要注意的是,用創(chuàng)建的函數(shù),其作用域指向全局作用域。所以,有另一種說法認為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實體。 作用域 定義 在編程語言中,作用域控制著變量與參數(shù)的可見性及生命周期,它能減少名稱沖突,而且提供了自動內(nèi)存管理 --javascript 語言精粹 我理解的是,一個變量、函數(shù)或者成員可以在代碼中訪問到的范圍。 js的變量作...
摘要:的分句會創(chuàng)建一個塊作用域,其聲明的變量僅在中有效。而閉包的神奇作用是阻止此事發(fā)生。依然持有對該作用域的引用,而這個引用就叫做閉包。當(dāng)然,無論使用何種方式對函數(shù)類型的值進行傳遞,當(dāng)函數(shù)在別處被調(diào)用時都可以觀察到閉包。 date: 16.12.8 Thursday 第一章 作用域是什么 LHS:賦值操作的目標(biāo)是誰? 比如: a = 2; RHS:誰是賦值操作的源頭? 比如: conso...
閱讀 3736·2021-11-24 09:39
閱讀 2617·2019-08-30 15:54
閱讀 1159·2019-08-30 13:01
閱讀 3436·2019-08-28 18:30
閱讀 1631·2019-08-26 17:44
閱讀 3598·2019-08-26 11:31
閱讀 2422·2019-08-26 10:40
閱讀 1252·2019-08-26 10:27