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)建的時候它的作用域鏈值入全局對象, 全局對象中有所有全局變量.如下圖所示(注意:圖片只列舉了全部變量中的一部分):

如果執(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);語句的作用域鏈如下:

在函數(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事件處理程序的作用域鏈是這樣的:

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