你不知道的JavaScript:作用域和閉包

最近看了《你不知道的JavaScript》這本書的上卷,感覺相當(dāng)不錯(cuò),一些以前模糊不清的感念從這本書里都弄懂了,下面是我的簡單的筆記,寫在這里權(quán)做記錄。


變量的賦值:編譯器在當(dāng)前作用域中聲明變量,運(yùn)行時(shí)引擎在作用域中查找該變量,并為其賦值

var a = 2; //相當(dāng)于var a; 和 a = 2;兩條指令

LHS和RHS,實(shí)際上相當(dāng)于左引用和右引用,也可以說是定值和引用,RHS查詢失敗拋出referenceError異常,LHS查詢失敗會隱式創(chuàng)建一個(gè)全局變量(非嚴(yán)格模式下),或者拋出referenceError異常(嚴(yán)格模式下)
referenceError作用域查找不到, typeError作用域鏈查找到了,但是類型錯(cuò)誤。

function foo(a) {
    console.log(a + b); //referenceError
    b = a;//創(chuàng)建一個(gè)全局變量
}
foo(2);

欺騙詞法(會被嚴(yán)格模式影響),導(dǎo)致無法在編譯時(shí)對作用域查找進(jìn)行優(yōu)化

  1. eval(),eval修改其所處的詞法作用域,就像eval中的代碼寫在這里一樣
function foo(str, a) {
    eval(str); //欺騙
    console.log(a, b);
}
var b = 2;
foo("var b = 3", 1); //1, 3

嚴(yán)格模式下eval有自己的詞法作用域。

function foo(str) {
    "use strict";
    eval(str); 
    console.log(a); // referenceError
}
foo("var a = 2"); //1, 3
  1. with(),根據(jù)傳遞給它的對象創(chuàng)建一個(gè)新的詞法作用域,將對象的屬性作為該對象中的標(biāo)識符
function foo(obj) {
    with(obj) {
        a = 2;
    }
}
var o1 = {
    a:3
};

var a2 = {
    b:3
};
foo(o1);
console.log(o1.a); // 2

foo(o2);
console.log(o2.a); //undefined
console.log(a); //2

函數(shù)聲明和函數(shù)表達(dá)式:名稱標(biāo)識符綁定的位置不同(函數(shù)所在作用域、函數(shù)本身)

//foo被綁定在所在作用域中
var a = 2;
function foo() {
    var a = 3;
    console.log(a); //3
}
foo();
console.log(a);//2

//函數(shù)聲明,foo只能在函數(shù)內(nèi)部使用,不會污染外部作用域
var a = 2;
(function foo() {
    var a = 3;
    console.log(a); //3
})();
console.log(a);//2

匿名函數(shù)缺點(diǎn):1. 調(diào)用棧更難追蹤;2. 自我引用更難;3. 代碼更難理解
塊作用域

  1. with:用with從對象中創(chuàng)建的作用域僅在with聲明中有效,
  2. catch:
try {
    undefined();//執(zhí)行一個(gè)非法操作來強(qiáng)制制造出一個(gè)異常
}
catch(err) {
    console.log(err);//可以正常執(zhí)行
}
console.log(err);//referenceError: err not found
  1. let為其聲明的變量隱式的劫持了所在的塊作用域(不會在塊內(nèi)進(jìn)行變量提升)
var foo = true;
if(foo) {
    let bar = foo *2;
    bar = something(bar);
    console.log(bar);
}
console.log(bar);//referenceError
  1. const,創(chuàng)建塊級作用域,值固定。

變量提升:函數(shù)優(yōu)先,且重復(fù)的var聲明會被忽略,但重復(fù)的函數(shù)聲明會覆蓋之前的聲明。
閉包:函數(shù)當(dāng)成值傳遞的時(shí)候,會出現(xiàn)閉包,因?yàn)楹瘮?shù)不是在其定義時(shí)所在的作用域里執(zhí)行,但執(zhí)行時(shí)仍保存了書寫位置的作用域

function foo() {
    var a = 2;
    function bar() {
        console.log(a);
    }
    return bar;
}
var baz = foo();
baz();//2,這就是閉包的效果

循環(huán)和閉包
共享閉包作用域、共享變量

for(var i = 0; i < 3; i++) {
    setTimeout(function timer() {
        console.log(i);  //3,3,3
    }, 0);
}

IIFE(立即執(zhí)行函數(shù)表達(dá)式)形成的作用域里并沒有內(nèi)容,仍然不行

for(var i = 0; i < 3; i++) {
    (function () {
        setTimeout(function timer() {
            console.log(i);  //3,3,3
        }, 0);
    })();
} 

每個(gè)迭代生成一個(gè)新的作用域,保存了正確的變量值

for(var i = 0; i < 3; i++) {
    (function () {
        var j = i;
        setTimeout(function timer() {
            console.log(j);  //0,1,2
        }, 0);
    })();
} 

let劫持塊作用域

for(var i = 0; i < 3; i++) {
    let j = i;  
    setTimeout(function timer() {
        console.log(j);  //0,1,2
    }, 0);
}

let表明i每次迭代聲明一次,并用上次迭代結(jié)束時(shí)的值初始化這個(gè)變量

for(let i = 0; i < 3; i++) {
    setTimeout(function timer() {
        console.log(j);  //0,1,2
    }, 0);
}

模塊
1、必須有外部封閉函數(shù),且至少執(zhí)行一次;2、封閉函數(shù)必須返回至少一個(gè)內(nèi)部函數(shù)

function CoolModule() {
    var something = 'cool';
    var another = [1, 2, 3];
    function doSomething() {
        console.log(something);
    }
    function doAnother() {
        console.log(another.join('!'));
    }
    return {
        ds: doSomething,
        da: doAnother
    };
}
var foo = CoolModule();
foo.ds();
foo.da();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,406評論 6 538
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,034評論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,413評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,449評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,165評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,559評論 1 325
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,606評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,781評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,327評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,084評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,278評論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,849評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,495評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,927評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,172評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,010評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,241評論 2 375

推薦閱讀更多精彩內(nèi)容