摘要:昨天我寫到所有函數(shù)都是閉包,有些同學(xué)表示還是接受不能。換句話說(shuō),它正是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。原因詳見(jiàn)我的上一篇文章從過(guò)程式到函數(shù)式。我的相關(guān)文章閉包從過(guò)程式到函數(shù)式以上所有代碼按授權(quán)。
昨天我寫到“所有Javascript函數(shù)都是閉包”,有些同學(xué)表示還是接受不能。我好好的一個(gè)函數(shù),怎么就成閉包了?那么,讓我們來(lái)探究一下,Chrome(V8)到底是怎樣實(shí)現(xiàn)閉包的。
從閉包到[[Scopes]]現(xiàn)在按下F12,打開(kāi)console,讓我們隨便找一個(gè)實(shí)驗(yàn)對(duì)象:
function simpleFunc() { } // <- undefined
超簡(jiǎn)單超正常的函數(shù)吧,我們來(lái)驗(yàn)證一下:
simpleFunc // <- ? simpleFunc() { }
說(shuō)了超正常的,哪里閉包了?現(xiàn)在試試這個(gè):
console.dir(simpleFunc) // ? simpleFunc() // arguments: null // caller: null // length: 0 // name: "simpleFunc" // prototype: {constructor: ?} // __proto__: ? () // [[FunctionLocation]]: VM000:1 // [[Scopes]]: Scopes[1]
咦,[[Scopes]]是什么?打開(kāi)一看:
// [[Scopes]]: Scopes[1] // 0: Global?{type: "global", name: "", object: Window}
這就是閉包的實(shí)現(xiàn)。東西都存在這里了。看起來(lái)simpleFunc只不過(guò)是純潔的函數(shù),但它實(shí)際上是(空的)自身代碼+全局變量環(huán)境。換句話說(shuō),它正是“函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合”。
再來(lái)個(gè)稍微復(fù)雜點(diǎn)的例子:
{ let localVar = 1; function dirtyFunc() { return localVar++ } } // <- ? dirtyFunc() { return localVar++ }
console.dir(dirtyFunc) // ? dirtyFunc() // [[Scopes]]: Scopes[2] // 0: Block // localVar: 1 // 1: Global {type: "global", name: "", object: Window}
看,localVar存在這里了吧!大家老說(shuō)什么“保持運(yùn)行的數(shù)據(jù)狀態(tài)”云云,其實(shí)都在[[Scopes]]里。dirtyFunc看起來(lái)是個(gè)普通的函數(shù),但[[Scopes]]里卻混了些東西。
所以,如果我們說(shuō)人話,閉包實(shí)際上就是——
函數(shù)的代碼+[[Scopes]]
超級(jí)好理解了吧。
寧愿用this也不用閉包接下來(lái)讓我們對(duì)閉包做些更深入的解析,然后就知道為什么大家寧愿用this也不用閉包了。
[[Scopes]]能用代碼訪問(wèn)/復(fù)制/修改嗎?不能。想不靠console,找到副作用在哪兒?不行。想深拷貝目前狀態(tài)?不行。想歷史回放?不行。debug?自己慢慢琢磨去吧!
閉包會(huì)把所有東西都存下來(lái)嗎?{ let localVar = 1; let unusedVar = 2; function dirtyFunc2() { return localVar++ } } console.dir(dirtyFunc2) // ? dirtyFunc() // [[Scopes]]: Scopes[2] // 0: Block // localVar: 1 // 1: Global {type: "global", name: "", object: Window}
至少Chrome是不會(huì)把所有東西都塞到閉包里的。
那閉包對(duì)垃圾回收沒(méi)害處?{ let localVar = new Uint8Array(1000000000) function dirtyFunc3() { return localVar } function cleanFunc() { } } var dirtyFunc3 = null console.dir(cleanFunc) // ? cleanFunc() // [[Scopes]]: Scopes[2] // 0: Block // localVar: Uint8Array(1000000000) [0, 0, …] // 1: Global {type: "global", name: "", object: Window}
dirtyFunc3和cleanFunc共享同一個(gè)[[Scopes]]項(xiàng),但這個(gè)[[Scopes]]項(xiàng)并不會(huì)因?yàn)?b>dirtyFunc3被回收而動(dòng)態(tài)更新!所以無(wú)辜的cleanFunc就只好一直帶著這1GB的垃圾,內(nèi)存泄漏妥妥的。作為強(qiáng)迫癥,這是我討厭閉包最重要的原因。
真的所有Javascript函數(shù)都是閉包嗎?console.dir(alert) // ? dirtyFunc() // [[Scopes]]: Scopes[0] // No properties
抱歉,我可能是不太嚴(yán)謹(jǐn)。很明顯,瀏覽器自帶的原生API函數(shù)都是在【里世界】聲明的,所以沒(méi)有詞法環(huán)境,自然[[Scopes]]是空的。它們不是閉包。
最佳實(shí)踐寧愿用this也不用閉包。原因詳見(jiàn)我的上一篇文章(從過(guò)程式到函數(shù)式)。
我的相關(guān)文章Javascript閉包:從過(guò)程式到函數(shù)式
以上所有代碼按Mozilla Public License, v. 2.0授權(quán)。
以上所有文字內(nèi)容按CC BY-NC-ND 4.0授權(quán)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/95497.html
摘要:想方設(shè)法糅合過(guò)程式與函數(shù)式兩種風(fēng)格,忽略了閉包的基本假設(shè),于是造出天坑。分散在各個(gè)閉包中的狀態(tài)會(huì)成為的溫床。當(dāng)然,嚴(yán)格來(lái)說(shuō)箭頭函數(shù)也是一種閉包,因?yàn)樗呛瘮?shù)和詞法的組合。 編程語(yǔ)言的究極問(wèn)題:過(guò)程式還是函數(shù)式? 閉包是函數(shù)式編程最先引進(jìn)的,基本假設(shè)就是所有量都是常量。Javascript想方設(shè)法糅合過(guò)程式與函數(shù)式兩種風(fēng)格,忽略了閉包的基本假設(shè),于是造出天坑。 是什么 閉包的定義是函數(shù)和...
摘要:所以,有另一種說(shuō)法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。所以本文中將以維基百科中的定義為準(zhǔn)即在計(jì)算機(jī)科學(xué)中,閉包,又稱詞法閉包或函數(shù)閉包,是引用了自由變量的函數(shù)。 閉包(closure)是JavaScript中一個(gè)神秘的概念,許多人都對(duì)它難以理解,我也一直處于似懂非懂的狀態(tài),前幾天深入了解了一下執(zhí)行環(huán)境以及作用域鏈,可戳查看詳情,而閉包與作用域及作用域鏈的關(guān)系密不可分,所...
摘要:在一個(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í)向上尋找...
摘要:項(xiàng)目地址閉包在計(jì)算機(jī)科學(xué)中,閉包英語(yǔ),又稱詞法閉包或函數(shù)閉包,是引用了自由變量的函數(shù)。這個(gè)被引用的自由變量將和這個(gè)函數(shù)一同存在,即使已經(jīng)離開(kāi)了創(chuàng)造它的環(huán)境也不例外。 項(xiàng)目地址:https://git.io/pytips 閉包(Closure) 在計(jì)算機(jī)科學(xué)中,閉包(英語(yǔ):Closure),又稱詞法閉包(Lexical Closure)或函數(shù)閉包(function closures),是...
摘要:全局環(huán)境是作用域鏈的終點(diǎn)。環(huán)境記錄類型定義了兩種環(huán)境記錄類型聲明式環(huán)境記錄和對(duì)象環(huán)境記錄聲明式環(huán)境記錄聲明式環(huán)境記錄是用來(lái)處理函數(shù)作用域中出現(xiàn)的變量,函數(shù),形參等。變量環(huán)境變量環(huán)境就是存儲(chǔ)上下文中的變量和函數(shù)的。解析的過(guò)程如下 原文 ECMA-262-5 in detail. Chapter 3.2. Lexical environments: ECMAScript implement...
閱讀 2942·2023-04-26 01:32
閱讀 1541·2021-09-13 10:37
閱讀 2278·2019-08-30 15:56
閱讀 1670·2019-08-30 14:00
閱讀 3043·2019-08-30 12:44
閱讀 1961·2019-08-26 12:20
閱讀 1058·2019-08-23 16:29
閱讀 3228·2019-08-23 14:44