第4章 提升
-
var a = 2引擎會(huì)將這條語句分為var a和a = 2,一個(gè)是聲明變量,編譯階段的任務(wù),而第二個(gè)是賦值,執(zhí)行階段的任務(wù)。 - 提升是指無論作用域中的聲明出現(xiàn)在什么地方,都會(huì)在編譯階段放到最前面首先進(jìn)行處理。這個(gè)過程將變量和函數(shù)移動(dòng)到給自的作用域最頂端,這個(gè)過程被稱為”提升“
- 函數(shù)聲明首先被提升,然后才是變量
- 函數(shù)表達(dá)式中的變量聲明會(huì)被提升,但是賦值操作不會(huì)。
- 這段代碼輸出的是b,因?yàn)楹瘮?shù)聲明被提升了,并且被覆蓋了
foo(); // "b"
var a = true;
if (a) {
function foo() { console.log("a"); }
}
else {
function foo() { console.log("b"); }
}
第5章 作用域閉包
閉包是前端很重要的概念,但是很少有人能分辨清楚什么是閉包,并且如何去使用閉包。很多人認(rèn)為函數(shù)里嵌套函數(shù)就是閉包,我認(rèn)為是不對(duì)的。這本書里很好的幫我理清楚了閉包到底是什么。
- 當(dāng)函數(shù)可以記住并訪問所在的詞法作用域時(shí),就產(chǎn)生了閉包。即使函數(shù)是在當(dāng)前詞法作用域之外執(zhí)行的。
function foo() {
var a = 2;
function bar() {
console.log( a ); // 2
}
bar();
}
foo();
按照上面的定義,這是閉包嗎?從技術(shù)上來說,函數(shù)bar具有一個(gè)涵蓋foo作用域的閉包,但是我們無法從上面代碼看得出閉包如何工作的。看下面這段代碼:
function foo() {
var a = 2;
function bar() {
console.log( a );
}
return bar;
}
var baz = foo();
baz(); // 2 —— 朋友,這就是閉包的效果。
Baz返回的是bar函數(shù),bar() 顯然是調(diào)用的地方是在自己定義的詞法作用域以外的地方執(zhí)行。一般情況,foo執(zhí)行結(jié)束后,通常會(huì)期待foo()的整個(gè)內(nèi)部作用域都會(huì)被銷毀,但是因?yàn)殚]包的作用,bar()所聲明的地方位置的隱私,它擁有foo的內(nèi)部作用域的閉包,所以不會(huì)不銷毀。bar的這個(gè)引用就叫做閉包。
- 無論何種方式的函數(shù)值傳遞,我們都可以看見閉包的作用
function foo() {
var a = 2;
function baz() {
console.log( a ); // 2
}
bar( baz );
}
function bar(fn) {
fn(); // 媽媽快看呀,這就是閉包!
}
var fn;
function foo() {
var a = 2;
function baz() {
console.log( a );
}
fn = baz; // 將 baz 分配給全局變量
}
function bar() {
fn(); // 媽媽快看呀,這就是閉包!
}
foo();
bar(); // 2
- setTimeout, 事件監(jiān)聽器,ajax請(qǐng)求,跨窗口通信,異步任務(wù)等,只要用到了回調(diào)函數(shù),實(shí)際上就是在使用閉包。
循環(huán)和閉包
- 觀察這段代碼,執(zhí)行結(jié)果:回調(diào)函數(shù)會(huì)在循環(huán)結(jié)束后執(zhí)行,因?yàn)槊看窝h(huán)都會(huì)賦值上一次運(yùn)行的值,繼續(xù)運(yùn)行。
for (var i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
- 對(duì)比和上面代碼區(qū)別
for (var i=1; i<=5; i++) {
(function() {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
})();
}
IIFE 會(huì)通過聲明并立即執(zhí)行一個(gè)函數(shù)來創(chuàng)建作用域,雖然有了獨(dú)立的作用域但是什么都沒有,需要一個(gè)變量存儲(chǔ)變量才行
for (var i=1; i<=5; i++) {
(function() {
var j = i;
setTimeout( function timer() {
console.log( j );
}, j*1000 );
})();
}
//改進(jìn)后
for (var i=1; i<=5; i++) {
(function(j) {
setTimeout( function timer() {
console.log( j );
}, j*1000 );
})( i );
}
這里才是預(yù)期的效果,一段時(shí)間后輸出循環(huán)的參數(shù)。
小結(jié): 這部分還需要再多看幾遍,有一種似懂非懂的感覺,還不能十分把握說清楚。