JavaScript進(jìn)階必學(xué)之作用域、GC?垃圾回收、閉包詳解
前言:
本文系統(tǒng)講解JavaScript核心知識,涵蓋作用域、作用域鏈、垃圾回收、閉包與變量提升。結(jié)合案例拆解底層原理,通俗易懂梳理關(guān)鍵概念與應(yīng)用場景,夯實(shí)前端基礎(chǔ),助力高效理解JS底層邏輯。

一:作用域
介紹:
作用域(scope)規(guī)定了變量能夠被訪問的 “范圍”,離開了這個(gè) “范圍” 變量便不能被訪問
作用域分為:
局部作用域
全局作用域
局部作用域
局部作用域又分為函數(shù)作用域和塊作用域。
函數(shù)作用域:
在函數(shù)內(nèi)部聲明的變量只能在函數(shù)內(nèi)部被訪問,外部無法直接訪問。
<script>
function getSum() {
// 函數(shù)內(nèi)部是函數(shù)作用域 屬于局部變量
const num = 10
}
console.log(num) // 此處報(bào)錯(cuò) 函數(shù)外部不能使用局部作用域變量
</script>
總結(jié):
函數(shù)內(nèi)部聲明的變量,在函數(shù)外部無法被訪問
函數(shù)的參數(shù)也是函數(shù)內(nèi)部的局部變量
不同函數(shù)內(nèi)部聲明的變量無法互相訪問
函數(shù)執(zhí)行完畢后,函數(shù)內(nèi)部的變量實(shí)際被清空了
塊作用域:
在 JavaScript 中使用 {} 包裹的代碼稱為代碼塊,代碼塊內(nèi)部聲明的變量外部將【有可能】(當(dāng)是var的時(shí)候可以被訪問)無法被訪問。
for (let t = 1; t <= 6; t++) {
// t 只能在該代碼塊中被訪問
console.log(t) // 正常
}
// 超出了 t 的作用域
console.log(t) // 報(bào)錯(cuò)
let 聲明的變量會產(chǎn)生塊作用域,var 不會產(chǎn)生塊作用域
const 聲明的常量也會產(chǎn)生塊作用域
不同代碼塊之間的變量無法互相訪問
推薦使用 let 或 const
全局作用域
<script> 標(biāo)簽和 .js 文件的【最外層】就是所謂的全局作用域,在此聲明的變量在函數(shù)內(nèi)部也可以被訪問。
全局作用域中聲明的變量,任何其它作用域都可以被訪問。
<script>
// 全局作用域
// 全局作用域下聲明了 num 變量
const num = 10
function fn() {
// 函數(shù)內(nèi)部可以使用全局作用域的變量
console.log(num)
}
// 此處全局作用域
</script>
注意:
為 window 對象動態(tài)添加的屬性默認(rèn)也是全局的,不推薦!
函數(shù)中未使用任何關(guān)鍵字聲明的變量為全局變量,不推薦?。?!
盡可能少的聲明全局變量,防止全局變量被污染
二:作用域鏈
作用域鏈本質(zhì)上是底層的變量查找機(jī)制。
在函數(shù)被執(zhí)行時(shí),會優(yōu)先查找當(dāng)前函數(shù)作用域中查找變量
如果當(dāng)前作用域查找不到則會依次逐級查找父級作用域直到全局作用域
<script>
// 全局作用域
let a = 1
let b = 2
// 局部作用域
function f() {
let a = 1
// 局部作用域
function g() {
a = 2
console.log(a)
}
g() // 調(diào)用g
}
f() // 調(diào)用f
</script>
總結(jié):
嵌套關(guān)系的作用域串聯(lián)起來形成了作用域鏈
相同作用域鏈中按著從小到大的規(guī)則查找變量
子作用域能夠訪問父作用域,父級作用域無法訪問子級作用域
三:垃圾回收機(jī)制
垃圾回收機(jī)制 (Garbage Collection) 簡稱 GC
JS 中內(nèi)存的分配和回收都是自動完成的,內(nèi)存在不使用的時(shí)候會被垃圾回收器自動回收
內(nèi)存的生命周期
JS 環(huán)境中分配的內(nèi)存,一般有如下生命周期:
內(nèi)存分配:當(dāng)我們聲明變量、函數(shù)、對象的時(shí)候,系統(tǒng)會自動為他們分配內(nèi)存
內(nèi)存使用:即讀寫內(nèi)存,也就是使用變量、函數(shù)等
內(nèi)存回收:使用完畢,由垃圾回收器自動回收不再使用的內(nèi)存
// 為變量分配內(nèi)存
const age = 18
// 為對象分配內(nèi)存
const obj = {
age: 19
}
// 為函數(shù)分配內(nèi)存
function fn() {
const age = 18
console.log(age)
}
說明:
全局變量一般不會回收(關(guān)閉頁面回收)
一般情況下局部變量的值,不用了,會被自動回收掉
內(nèi)存泄漏:程序中分配的內(nèi)存由于某種原因程序未釋放或無法釋放叫做內(nèi)存泄漏
拓展 - JS 垃圾回收機(jī)制 - 算法說明
堆??臻g分配區(qū)別:
棧(操作系統(tǒng)):由操作系統(tǒng)自動分配釋放函數(shù)的參數(shù)值、局部變量等,基本數(shù)據(jù)類型放到棧里面。
堆(操作系統(tǒng)):一般由程序員分配釋放,若程序員不釋放,由垃圾回收機(jī)制回收。復(fù)雜數(shù)據(jù)類型放到堆里面。
引用計(jì)數(shù)法 :
IE 采用的引用計(jì)數(shù)算法,定義 “內(nèi)存不再使用”,就是看一個(gè)對象是否有指向它的引用,沒有引用了就回收對象
算法:
跟蹤記錄被引用的次數(shù)
如果被引用了一次,那么就記錄次數(shù) 1,多次引用會 ++
如果減少一個(gè)引用就減 1 –
如果引用次數(shù)是 0,則釋放內(nèi)存
但它卻存在一個(gè)致命的問題:嵌套引用(循環(huán)引用)
如果兩個(gè)對象相互引用,盡管他們已不再使用,垃圾回收器不會進(jìn)行回收,導(dǎo)致內(nèi)存泄漏。
function fn() {
let o1 = {}
let o2 = {}
o1.a = o2
o2.a = o1
return '引用計(jì)數(shù)無法回收'
}
fn()
因?yàn)樗麄兊囊么螖?shù)永遠(yuǎn)不會是 0。這樣的相互引用如果說很大量的存在就會導(dǎo)致大量的內(nèi)存泄漏。
標(biāo)記清除法
標(biāo)記清除算法將 “不再使用的對象” 定義為 “無法達(dá)到的對象”。
就是從根部(在 JS 中就是全局對象)出發(fā)定時(shí)掃描內(nèi)存中的對象。凡是能從根部到達(dá)的對象,都是還需要使用的。
那些無法由根部出發(fā)觸及到的對象被標(biāo)記為不再使用,稍后進(jìn)行回收。
解決內(nèi)存泄漏問題
四:閉包
概念:一個(gè)函數(shù)對周圍狀態(tài)的引用捆綁在一起,內(nèi)層函數(shù)中訪問到其外層函數(shù)的作用域
簡單理解:閉包 = 內(nèi)層函數(shù) + 外層函數(shù)的變量
function outer() {
const a = 1
function f() {
console.log(a)
}
f()
}
outer()
閉包應(yīng)用:實(shí)現(xiàn)數(shù)據(jù)的私有
比如,我們要做個(gè)統(tǒng)計(jì)函數(shù)調(diào)用次數(shù),函數(shù)調(diào)用一次,就 ++
let count = 1
function fn() {
count++
console.log(`函數(shù)被調(diào)用${count}次`)
}
fn() // 2
fn() // 3
但是,這個(gè) count 是個(gè)全局變量,很容易被修改
function fn() {
let count = 1
function fun() {
count++
console.log(`函數(shù)被調(diào)用${count}次`)
}
return fun
}
const result = fn()
result() // 2
result() // 3
這樣實(shí)現(xiàn)了數(shù)據(jù)私有,無法直接修改 count
五:變量提升
變量提升是 JavaScript 中比較 “奇怪” 的現(xiàn)象,它允許在變量聲明之前即被訪問(僅存在于 var 聲明變量)
注意:
變量在未聲明即被訪問時(shí)會報(bào)語法錯(cuò)誤
變量在 var 聲明之前即被訪問,變量的值為 undefined
let/const 聲明的變量不存在變量提升
變量提升出現(xiàn)在相同作用域當(dāng)中
實(shí)際開發(fā)中推薦先聲明再訪問變量
<script> // 訪問變量 str console.log(str + 'world!') // 聲明變量 str var str = 'hello ' </script>
最后:
到此這篇關(guān)于JavaScript進(jìn)階必學(xué)之作用域、GC 垃圾回收、閉包的文章就介紹到這了,更多相關(guān)JS作用域、GC 垃圾回收、閉包內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript中錯(cuò)誤正確處理方式小結(jié)你用對了嗎
本文將會討論客戶端JavaScript中的錯(cuò)誤處理。主要介紹JavaScript中的易犯錯(cuò)誤、錯(cuò)誤處理、異步代碼編寫等內(nèi)容。下面就讓我們一起看看如何正確處理JavaScript中的錯(cuò)誤2017-10-10
JavaScript SHA1加密算法實(shí)現(xiàn)詳細(xì)代碼
這篇文章主要為大家詳細(xì)介紹了JavaScript SHA1加密算法實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的朋友可以參考一下2016-10-10
js實(shí)現(xiàn)橫向百葉窗效果網(wǎng)頁切換動畫效果的方法
這篇文章主要介紹了js實(shí)現(xiàn)橫向百葉窗效果網(wǎng)頁切換動畫效果的方法,實(shí)例分析了javascript實(shí)現(xiàn)百葉窗效果的技巧,需要的朋友可以參考下2015-03-03

