前端學(xué)習(xí)指南第二天:徹底理解作用域,作用域鏈和閉包

5作用域:作用域簡單說就是函數(shù)和變量能夠訪問的范圍,控制變量的可見性和生命周期。其中包含了局部作用域和全局作用域。

變量沒有在函數(shù)內(nèi)聲明或聲明的時候沒有帶var就是全局變量, 擁有全局作用域, window對象的所有屬性擁有全局作用域;在代碼的任何地方都可以訪問,

函數(shù)內(nèi)部聲明并且以var修飾的變量就是局部變量, 只能在函數(shù)體內(nèi)使用, 函數(shù)的參數(shù)雖然沒有使用var但仍然是局部變量.

以下是比較讓人迷惑的地方
javascript沒用塊級作用域,只有函數(shù)級作用域,這里要理解一下js的聲明提前(聲明提前:在函數(shù)內(nèi)部,不管在哪里聲明,其實他們都是統(tǒng)一被放在函數(shù)頂部被聲明。所以通常的做法是在函數(shù)頂部統(tǒng)一聲明變量。)。

console.log(a);//undefined,雖然var a =3,會提前這句聲明,但是只會預(yù)解析到var a,并不會執(zhí)行賦值操作 a=3,所以未定義
var a =3;
consloe.log(a);//3執(zhí)行完賦值語句自然得到3

但我們可以模仿塊級作用域

(function(){
//這里就是塊級作用域,這其實也是立即執(zhí)行函數(shù)
})

作用域鏈:
當(dāng)代碼在一個環(huán)境中執(zhí)行時, 會創(chuàng)建變量對象的一個作用域鏈(scope chain)來保證對執(zhí)行環(huán)境有權(quán)訪問的變量和函數(shù)的有序訪問. 作用域第一個對象始終是當(dāng)前執(zhí)行代碼所在的環(huán)境變量對象(VO).

function a(x, y){
    var b = x + y;
    return b;
}

在函數(shù)a創(chuàng)建的時候它的作用域鏈值入全局對象, 全局對象中有所有全局變量.如下圖所示(注意:圖片只列舉了全部變量中的一部分):


Paste_Image.png

如果執(zhí)行環(huán)境是函數(shù), 那么將其活動對象(activation object, AO)作為作用域鏈第一個對象, 第二個對象是包含環(huán)境, 下一個是包含環(huán)境的包含環(huán)境...

function a(x, y){
    var b= x + y;
    return b;
}
var t = a(5, 10);

這時候, var t = a(5, 10);語句的作用域鏈如下:


Paste_Image.png

在函數(shù)運行過程中, 標(biāo)識符的解析是沿著作用域鏈一級一級搜索的過程, 從第一個對象開始, 逐級向上回溯(由下至上), 直到找到同名標(biāo)識符為止, 找到后不再繼續(xù)遍歷, 找不到就報錯.

閉包:

背景:
根據(jù)作用域和作用域鏈的原理,我們似乎不能在外部讀取其它函數(shù)的內(nèi)部變量。
閉包:
閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù),在js中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,因此可以把閉包簡單理解成“定義在一個函數(shù)內(nèi)部的函數(shù)”。
只要存在調(diào)用內(nèi)部函數(shù)的可能, JavaScript就需要保留被引用的函數(shù), 而且JavaScript運行時需要跟蹤引用這個內(nèi)部函數(shù)的所有變量, 直到最后一個變量廢棄, JavaScript的垃圾回收器才能釋放相應(yīng)的內(nèi)存空間.
本質(zhì)上,閉包是函數(shù)內(nèi)外部的橋梁。
原理:
1.后臺執(zhí)行環(huán)境中,閉包的作用域鏈包含著自己的作用域、函數(shù)的作用域和全局作用域。
2.通常,函數(shù)的作用域和變量會在函數(shù)執(zhí)行結(jié)束后銷毀。
3.但是,當(dāng)函數(shù)返回一個閉包時,這個函數(shù)的作用域?qū)恢痹趦?nèi)存中保存到閉包不存在為止。
用途:
1.訪問函數(shù)內(nèi)部變量,就是實現(xiàn)面向?qū)ο蟮脑L問控制。也就是c++, c#, java等面向?qū)ο蟮膒rivate, public訪問控制
2.將這些變量值始終保存在內(nèi)存
缺點:
1.需要維護額外的作用域
2.過渡使用閉包會占用大量內(nèi)存

for(var i=0; i<eles.length; i++){
    eles[i].onclick = function(){
        alert(i);
    }
}

每次點擊eles alert的值都是length, 這代碼中為eles綁定的click事件處理程序的作用域鏈是這樣的:


Paste_Image.png

由于內(nèi)部函數(shù)(click事件處理程序時刻有調(diào)用可能), 所以其作用域鏈不能被銷毀(更別說本例中i在全局作用域中, 只能在頁面關(guān)閉時銷毀), i的值一直保持for循環(huán)執(zhí)行完后的length的值, 所以每次觸發(fā)onclick的時候才會alert length.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容