一、幾個(gè)概念村生,
執(zhí)行環(huán)境(execution context)惊暴,定義了變量或函數(shù)有權(quán)訪問的其他數(shù)據(jù),決定了它們各自的行為梆造。
變量對(duì)象(variable object)缴守,環(huán)境中定義的所有變量和函數(shù)都保存在這個(gè)對(duì)象中葬毫。如果該環(huán)境是函數(shù),變量對(duì)象就是活動(dòng)對(duì)象屡穗,活動(dòng)對(duì)象最初只包含一個(gè)變量贴捡,即 arguments 對(duì)象。
每個(gè)執(zhí)行環(huán)境都有一個(gè)與之關(guān)聯(lián)的變量對(duì)象村砂。
某個(gè)執(zhí)行環(huán)境中的所有代碼執(zhí)行完畢后烂斋,該環(huán)境被銷毀,保存在其中的所有變量和函數(shù)定義也隨之銷毀(全局執(zhí)行環(huán)境直到應(yīng)用程序退出础废,如關(guān)閉網(wǎng)頁或?yàn)g覽器汛骂,才被銷毀)。也就是進(jìn)行自動(dòng)垃圾回收评腺。
作用域鏈(scope chain)帘瞭,當(dāng)執(zhí)行流進(jìn)入一個(gè)函數(shù)時(shí),函數(shù)環(huán)境就會(huì)被推入一個(gè)環(huán)境棧蒿讥,在函數(shù)執(zhí)行之后蝶念,棧將其環(huán)境彈出,把控權(quán)返回給之前的執(zhí)行環(huán)境芋绸。作用域鏈就是環(huán)境棧媒殉。
二、有一段代碼摔敛,放在全局作用域中廷蓉,
function func1() {
console.log('func1');
function func2(){
console.log('func2');
}
func2();
}
function func3() {
console.log('func3');
}
func1();
func3();
這段代碼的作用域可以這樣理解,開始時(shí)马昙,作用域鏈(環(huán)境棧)只有 Global(Window)桃犬,當(dāng)執(zhí)行 func1(),作用域鏈(環(huán)境棧)推入 func1给猾,變成:
func1, Global
查找任何變量疫萤,先在 func1 的執(zhí)行環(huán)境中找,如果找不到敢伸,再在 Global 的執(zhí)行環(huán)境中找。
當(dāng)執(zhí)行到 func2()恒削,作用域鏈(環(huán)境棧)推入 func1池颈,變成:
func2, func1, Global
func2 執(zhí)行完畢后,func2 的環(huán)境被銷毀钓丰,內(nèi)存釋放躯砰,作用域鏈(環(huán)境棧)變?yōu)椋?/p>
func1, Global
func1 執(zhí)行完畢,作用域鏈(環(huán)境棧)變?yōu)椋?/p>
Global
再執(zhí)行 func3携丁,作用域鏈(環(huán)境棧)變?yōu)椋?/p>
func3, Global
func3 執(zhí)行完畢琢歇,作用域鏈(環(huán)境棧)變?yōu)椋?/p>
Global
當(dāng)瀏覽器(或標(biāo)簽)關(guān)閉兰怠,Global 銷毀。
正如這幅圖李茫,每個(gè)內(nèi)部作用域都可以依次訪問它外部的每個(gè)作用域揭保,但外部作用域不能訪問內(nèi)部作用域。
三魄宏、閉包
閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)秸侣。創(chuàng)建閉包的常見方式,是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)宠互。
閉包本質(zhì)上是味榛,函數(shù)執(zhí)行完畢后,若其活動(dòng)對(duì)象仍然被引用予跌,則執(zhí)行環(huán)境的作用域鏈會(huì)被銷毀搏色,但它的活動(dòng)對(duì)象仍然會(huì)留在內(nèi)存中。
由于閉包會(huì)攜帶包含它的函數(shù)的作用域券册,因此會(huì)比其他函數(shù)占用更多的內(nèi)存频轿。過度使用閉包可能會(huì)導(dǎo)致內(nèi)存占用過多,只在絕對(duì)必要時(shí)再考慮使用閉包汁掠。
閉包涉及的問題:
1.內(nèi)存泄漏略吨,應(yīng)該把不用的全局變量、全局函數(shù)考阱、引起循環(huán)引用的變量設(shè)置為 null
2.閉包保存著外部函數(shù)的作用域翠忠,因此無法獲得循環(huán)下標(biāo)
(function(){
var n=2;
for(var i=0; i< Math.pow(10, n); i++){
var button = document.createElement('button');
document.body.appendChild(button);
}
var buttonArray = document.getElementsByTagName('button');
for(var j=0; j<buttonArray.length; j++){
// 返回都是 10^n
buttonArray[j].onclick = function(){
console.log(j);
}
}
})();
3.閉包無法獲取 this,可以在外部把它保存起來
var self = this;