JavaScript作用域和變量提升

一变丧、JS的作用域

1.JS采用詞法作用域

首先,我們得知道JavaScript采取的是詞法作用域咸这,而不是動(dòng)態(tài)作用域夷恍。
那么什么是詞法作用域,什么是動(dòng)態(tài)作用域呢媳维?

引用一下我以前在知乎上看到的一句精簡(jiǎn)的描述:

詞法作用域的函數(shù)中遇到既不是形參也不是函數(shù)內(nèi)部定義的局部變量的變量時(shí)侄刽,去函數(shù)定義時(shí)的環(huán)境中查找醋安。

動(dòng)態(tài)作用域的函數(shù)中遇到既不是形參也不是函數(shù)內(nèi)部定義的局部變量的變量時(shí)墓毒,去函數(shù)調(diào)用時(shí)的環(huán)境中找柠辞。

如果對(duì)這句話還是不太明白的朋友,可以觀察以下代碼:

var a = "這是第一個(gè)a";
function func01() {
    console.log(a);         //先在當(dāng)前作用域中查找,如果沒(méi)有則訪問(wèn)全局的作用域
}

function func02() {
    var a = "這是第二個(gè)a";
    func01()
}

func01();       //打印結(jié)果為:這是第一個(gè)a
func02();       //打印結(jié)果為:這是第一個(gè)a(倘若JS用的是動(dòng)態(tài)作用域夷都,這里將輸出第二個(gè)a)

2.JS沒(méi)有塊作用域(try,catch為特例)

在大多數(shù)語(yǔ)言中摩泪,都是有塊作用域的嚷掠,比如C荞驴、C++霹娄、C#犬耻、Java、Object-C等等术吝,而JS沒(méi)有塊作用域峭咒。

下面分別是C和OC的代碼

#include <stdio.h>
int main() {
    int a = 1;
    if (1) {
        int a = 2;
        printf("%d, ", a); // 2
    }
    printf("%d\n", a); // 1
}
NSString *str = @"碼農(nóng)1號(hào)";  
if (true) {
    NSString *str = @"碼農(nóng)2號(hào)";
    NSLog(@"%@", str);  //碼農(nóng)2號(hào)
}
NSLog(@"%@", str);  //碼農(nóng)1號(hào)

在C和OC中幔翰,if花括號(hào)內(nèi)定義的變量遗增,在if語(yǔ)句執(zhí)行完后饰及,就被銷毀了屏箍。那么我們?cè)賮?lái)看看類似的代碼運(yùn)行在JS中赴魁。

var a = "global";
if (true) {
    var a = "if";
    console.log(a);  //if
}
console.log(a);  //輸出為:if  證明if語(yǔ)句內(nèi)定義的變量颖御,是全局變量  

那么在JS中,我們能否像其它語(yǔ)言一樣創(chuàng)建出類似塊作用域的效果呢泽铛?答案是可以的尚辑,利用閉包!

因?yàn)樵贘S在只存在全局作用域函數(shù)作用域盔腔,因此我們可以巧妙的利用一下函數(shù)作用域創(chuàng)建出塊作用域的效果杠茬,我們把上面的JS代碼改造一下:

var a = "global";
if (true) {
    (function() {
        var a = "if";
        console.log(a);  //if
    })();
}
console.log(a);  //global  

上面代碼在if內(nèi)創(chuàng)建了一個(gè)閉包,它是一個(gè)立即調(diào)用的匿名函數(shù)弛随,因此這里創(chuàng)建出了一個(gè)函數(shù)作用域瓢喉,在此函數(shù)作用域里定義的變量,將不影響全局變量舀透,并且函數(shù)執(zhí)行完后栓票,該變量會(huì)被銷毀。
這樣利用閉包的好處是:限定作用域愕够,不怕污染全局變量走贪。

二、JS中的變量提升和函數(shù)提升

1.變量的提升

在JS代碼編譯時(shí)惑芭,函數(shù)聲明和變量定義會(huì)被解釋器移動(dòng)到其所在作用域的最頂部坠狡!

怎么理解這句話呢?我們來(lái)看下面代碼

console.log(a); //報(bào)錯(cuò)
console.log(a);  //undefined
var a = 10;

為什么上面代碼不報(bào)錯(cuò)遂跟?因?yàn)樯厦娲a在編譯器解析完后逃沿,變成了下面的形式:

var a;
console.log(a);
a = 10;

那么我們?cè)倏聪旅娴睦佑ざ桑虏滤鼈兊妮敵鼋Y(jié)果

var a = "global";
fun();
function fun() {
  console.log(a); //1.?
  var a = "local";
}
console.log(a); //2.凯亮?

輸出結(jié)果是 1. undefined边臼, 2. global

上面的代碼的正確解析如下:

var a;
function fun() {     
  var a;    //此變量所處域?yàn)楹瘮?shù)域,因此其作用域最頂部是這里
  console.log(a); //undefined
  a = "local";
}
a = "global"
fun();
console.log(a);   //global   (函數(shù)域創(chuàng)建的變量不污染到外面)

2.函數(shù)表達(dá)式的提升(非函數(shù)聲明)

先看例子:

console.log(fun);  //undefined
var fun = function () {
  console.log("我是一個(gè)函數(shù)");
}

上面的函數(shù)提升跟變量的提升一樣触幼,解析完如下:

var fun;
console.log(fun);  //undefined
fun = function () {
  console.log("我是一個(gè)函數(shù)");
}

3.函數(shù)聲明的提升

先看例子:

console.log(fun);  //整個(gè)函數(shù)打印出來(lái)
function fun() {
  console.log("我是一個(gè)函數(shù)");
}

解析完如下:

function fun() {
  console.log("我是一個(gè)函數(shù)");
}
console.log(fun);  //整個(gè)函數(shù)打印出來(lái)

由此我們可以得出結(jié)論:JavaScript編譯時(shí)硼瓣,對(duì)于函數(shù)表達(dá)式的提升是跟普通變量提升一樣的,僅提升聲明但不賦值置谦。對(duì)于函數(shù)聲明的提升堂鲤,則是整個(gè)提升,我們可以理解為聲明+賦值的提升媒峡。

總結(jié):

  1. 只有函數(shù)可以限定作用域

  2. 在函數(shù)內(nèi)部允許訪問(wèn)外部的變量瘟栖,但外部不能訪問(wèn)函數(shù)內(nèi)部變量

  3. 如果當(dāng)前作用域中有該變量,則不考慮外部作用域的同名變量

  4. 對(duì)于變量和函數(shù)表達(dá)式的提升,僅提升聲明谅阿,不賦值

  5. 對(duì)于函數(shù)聲明的提升半哟,是聲明+賦值

本農(nóng)搞了個(gè)小練習(xí)給大家練練手,如果做對(duì)基本對(duì)于該文你也就懂了签餐,先不要看最下面的解析結(jié)果

var a = "global";
function fun() {
    a = "local";
    return;
    function a() {}
}
fun();
alert(a);

解析結(jié)果為:

var a;
function fun() {
    function a() {}   
    a = "local";
    return;
}
a = "global"
fun();      //function a(){} 可以理解為 var a = function(){}寓涨,函數(shù)域內(nèi)聲明的變量不影響全局
alert(a);  //輸出為global
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市氯檐,隨后出現(xiàn)的幾起案子戒良,更是在濱河造成了極大的恐慌,老刑警劉巖冠摄,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件糯崎,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡河泳,警方通過(guò)查閱死者的電腦和手機(jī)沃呢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拆挥,“玉大人薄霜,你說(shuō)我怎么就攤上這事≈酵茫” “怎么了惰瓜?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)食拜。 經(jīng)常有香客問(wèn)我,道長(zhǎng)副编,這世上最難降的妖魔是什么负甸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上呻待,老公的妹妹穿的比我還像新娘打月。我一直安慰自己,他們只是感情好蚕捉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開(kāi)白布奏篙。 她就那樣靜靜地躺著,像睡著了一般迫淹。 火紅的嫁衣襯著肌膚如雪秘通。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,215評(píng)論 1 299
  • 那天敛熬,我揣著相機(jī)與錄音肺稀,去河邊找鬼。 笑死应民,一個(gè)胖子當(dāng)著我的面吹牛话原,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播诲锹,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼繁仁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了归园?” 一聲冷哼從身側(cè)響起黄虱,我...
    開(kāi)封第一講書(shū)人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蔓倍,沒(méi)想到半個(gè)月后悬钳,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡偶翅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年默勾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片聚谁。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡母剥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出形导,到底是詐尸還是另有隱情环疼,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布朵耕,位于F島的核電站炫隶,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏阎曹。R本人自食惡果不足惜伪阶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一煞檩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧栅贴,春花似錦斟湃、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至坛缕,卻和暖如春墓猎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背祷膳。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工陶衅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人直晨。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓搀军,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親勇皇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子罩句,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

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

  • 目錄 1.靜態(tài)作用域與動(dòng)態(tài)作用域 2.變量的作用域 3.JavaScript 中變量的作用域 4.JavaScri...
    一縷殤流化隱半邊冰霜閱讀 7,091評(píng)論 37 113
  • 《你不知道的JavaScript》真的是一本好書(shū),閱讀這本書(shū)敛摘,我有多次“哦门烂,原來(lái)是這樣”的感覺(jué),以前自以為理解了(...
    然并阮閱讀 621評(píng)論 2 9
  • You don't KnowJS 引語(yǔ):你不懂的JS這本書(shū)?github上已經(jīng)有了7w的star最近也是張野大大給...
    Sleet閱讀 580評(píng)論 0 0
  • 我用沉默 代替憤怒 我用安靜 代替?zhèn)?我用目標(biāo) 代替疑惑 將心變得柔軟 因?yàn)橹?我被禰全然的愛(ài)著 而我也全然愛(ài)...
    鴻嬌姐姐閱讀 235評(píng)論 2 5
  • 十一月二十七號(hào)上午十點(diǎn)慨丐。 手機(jī)響了,是她泄私。我不知道該不該接房揭,因?yàn)槲覝?zhǔn)備放手了∩味耍可是她的舍友卻跟我說(shuō)她現(xiàn)在除了我什么...
    小筆閱讀 431評(píng)論 2 4