成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Javascript作用域和變量提升

whlong / 3380人閱讀

摘要:有何區(qū)別在中,存在關(guān)鍵字,它聲明的變量同樣存在塊級作用域。而且函數(shù)本身的作用域,只存在其所在的塊級作用域之內(nèi),例如重復(fù)聲明一次函數(shù)上面這段代碼在中的輸出結(jié)果為因為被條件語句中的上升覆蓋了。如果對的使用,或的其他新特性感興趣,請自行閱讀文檔。

引子

首先大家看一下下面的代碼,猜猜會輸出什么結(jié)果?

var foo = 1;
function bar() {
    if (!foo) {
        var foo = 10;
    }
    alert(foo);
}
bar();

答案是10!
你是否會疑惑條件語句if(!foo)并不會執(zhí)行,為什么foo會被賦值為10

再來看第二個例子

var a = 1;
function b() {
    a = 10;
    return;
    function a() {}
}
b();
alert(a);

答案還是10嗎?顯然不是,alert輸出了1

如果你仍然對上面兩個輸出結(jié)果摸不著頭腦,那么請認(rèn)真閱讀這篇文章

Scoping in Javascript

Javascript的作用域已經(jīng)是老生常談的問題了,但是不一定每個人都能準(zhǔn)確理解。
我們先來看一下C語言的一個例子:

#include 
int main() {
    int x = 1;
    printf("%d, ", x); // 1
    if (1) {
        int x = 2;
        printf("%d, ", x); // 2
    }
    printf("%d
", x); // 1
}

程序依次輸出了1,2,1
為什么第三個輸出了1而不是2呢?因為在C語言中,我們有塊級作用域(block-level scope)。在一個代碼塊的中變量并不會覆蓋掉代碼塊外面的變量。我們不妨試一下Javascript中的表現(xiàn)

var x = 1;
console.log(x); // 1
if (true) {
    var x = 2;
    console.log(x); // 2
}
console.log(x); // 2

輸出的結(jié)果為1,2,2 if代碼塊中的變量覆蓋了全局變量。那是因為JavaScript是一種函數(shù)級作用域(function-level scope)所以if中并沒有獨立維護(hù)一個scope,變量x影響到了全局變量x

C,C++,C#和Java都是塊級作用域語言,那么在Javascript中,我們怎么實現(xiàn)一種類似塊級作用域的效果呢?答案是閉包

function foo() {
    var x = 1;
    if (x) {
        (function () {
            var x = 2;
            // some other code
        }());
    }
    // x is still 1.
}

上面代碼在if條件塊中創(chuàng)建了一個閉包,它是一個立即執(zhí)行函數(shù),所以相當(dāng)于我們又創(chuàng)建了一個函數(shù)作用域,所以內(nèi)部的x并不會對外部產(chǎn)生影響。

Hoisting in Javascript

在Javascript中,變量進(jìn)入一個作用域可以通過下面四種方式:

語言自定義變量:所有的作用域中都存在this和arguments這兩個默認(rèn)變量

函數(shù)形參:函數(shù)的形參存在函數(shù)作用域中

函數(shù)聲明:function foo() {}

變量定義:var foo

其中,___在代碼運行前,函數(shù)聲明和變量定義通常會被解釋器移動到其所在作用域的最頂部___,如何理解這句話呢?

function foo() {
    bar();
    var x = 1;
}

上面這段在嗎,被代碼解釋器編譯完后,將變成下面的形式:

function foo() {
    var x;
    bar();
    x = 1;
}

我們注意到,x變量的定義被移動到函數(shù)的最頂部。然后在bar()后,再對其進(jìn)行賦值。
再來看一個例子,下面兩段代碼其實是等價的:

function foo() {
    if (false) {
        var x = 1;
    }
    return;
    var y = 1;
}
function foo() {
    var x, y;
    if (false) {
        x = 1;
    }
    return;
    y = 1;
}

所以變量的上升(Hoisting)只是其定義上升,而變量的賦值并不會上升。

我們都知道,創(chuàng)建一個函數(shù)的方法有兩種,一種是通過函數(shù)聲明function foo(){}
另一種是通過定義一個變量var foo = function(){} 那這兩種在代碼執(zhí)行上有什么區(qū)別呢?

來看下面的例子:

function test() {
    foo(); // TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function () { // function expression assigned to local variable "foo"
        alert("this won"t run!");
    }
    function bar() { // function declaration, given the name "bar"
        alert("this will run!");
    }
}
test();

在這個例子中,foo()調(diào)用的時候報錯了,而bar能夠正常調(diào)用
我們前面說過變量會上升,所以var foo首先會上升到函數(shù)體頂部,然而此時的fooundefined,所以執(zhí)行報錯。而對于函數(shù)bar, 函數(shù)本身也是一種變量,所以也存在變量上升的現(xiàn)象,但是它是上升了整個函數(shù),所以bar()才能夠順利執(zhí)行。

再回到一開始我們提出的兩個例子,能理解其輸出原理了嗎?

var foo = 1;
function bar() {
    if (!foo) {
        var foo = 10;
    }
    alert(foo);
}
bar();

其實就是:

var foo = 1;
function bar() {
    var foo;
    if (!foo) {
        foo = 10;
    }
    alert(foo);
}
bar();
var a = 1;
function b() {
    a = 10;
    return;
    function a() {}
}
b();
alert(a);

其實就是:

var a = 1;
function b() {
    function a() {}
    a = 10;
    return;
}
b();
alert(a);

這就是為什么,我們寫代碼的時候,變量定義總要寫在最前面。

ES6有何區(qū)別

在ES6中,存在let關(guān)鍵字,它聲明的變量同樣存在塊級作用域。
而且函數(shù)本身的作用域,只存在其所在的塊級作用域之內(nèi),例如:

function f() { console.log("I am outside!"); }
if(true) {
   // 重復(fù)聲明一次函數(shù)f
   function f() { console.log("I am inside!"); }
}
f();

上面這段代碼在ES5中的輸出結(jié)果為I am inside!因為f被條件語句中的f上升覆蓋了。
在ES6中的輸出是I am outside!塊級中定義的函數(shù)不會影響外部。

如果對let的使用,或ES6的其他新特性感興趣,請自行閱讀ES6文檔。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/85885.html

相關(guān)文章

  • JavaScript作用域和閉包

    摘要:依然持有對該作用域的引用,而這個引用就叫作閉包。循環(huán)和閉包正常情況下,我們對這段代碼行為的預(yù)期是分別輸出數(shù)字,每秒一次,每次一個。 一、作用域 作用域共有兩種主要的工作模型:第一種是最為普遍的,被大多數(shù)編程語言所采用的詞法作用域,另外一種叫作動態(tài)作用域; JavaScript所采用的作用域模式是詞法作用域。 1.詞法作用域 詞法作用域意味著作用域是由書寫代碼時函數(shù)聲明的位置來決定...

    animabear 評論0 收藏0
  • JavaScript作用域和閉包

    摘要:依然持有對該作用域的引用,而這個引用就叫作閉包。循環(huán)和閉包正常情況下,我們對這段代碼行為的預(yù)期是分別輸出數(shù)字,每秒一次,每次一個。 一、作用域 作用域共有兩種主要的工作模型:第一種是最為普遍的,被大多數(shù)編程語言所采用的詞法作用域,另外一種叫作動態(tài)作用域; JavaScript所采用的作用域模式是詞法作用域。 1.詞法作用域 詞法作用域意味著作用域是由書寫代碼時函數(shù)聲明的位置來決定...

    CNZPH 評論0 收藏0
  • 關(guān)于javascript中的作用域和作用域鏈

    摘要:作用域的類別可以影響到變量的取值,分為詞法作用域靜態(tài)作用域和動態(tài)作用域。而,采用的就是詞法作用域,或者叫靜態(tài)作用域。 關(guān)于javascript中的作用域和作用域鏈 我GitHub上的菜鳥倉庫地址: 點擊跳轉(zhuǎn)查看其他相關(guān)文章 文章在我的博客上的地址: 點擊跳轉(zhuǎn) ? ? ? ? 前面的文章說到, 執(zhí)行上下文的創(chuàng)建階段,主要有三個內(nèi)容: ? ? ? ? 1、創(chuàng)建變量對象;2、初始化作用域...

    lcodecorex 評論0 收藏0
  • 你應(yīng)該要知道的作用域和閉包

    摘要:寫在前面對于一個前端開發(fā)者,應(yīng)該沒有不知道作用域的。欺騙詞法作用域有兩個機(jī)制可以欺騙詞法作用域和。關(guān)于你不知道的的第一部分作用域和閉包已經(jīng)結(jié)束了,但是,更新不會就此止住未完待續(xù) 這是《你不知道的JavaScript》的第一部分。 本系列持續(xù)更新中,Github 地址請查閱這里。 寫在前面 對于一個前端開發(fā)者,應(yīng)該沒有不知道作用域的。它是一個既簡單有復(fù)雜的概念,簡單到每行代碼都有它的影子...

    JouyPub 評論0 收藏0
  • JavaScript面向?qū)ο髜 作用域和閉包

    摘要:大名鼎鼎的作用域和閉包,面試經(jīng)常會問到。聲明理解閉包,先理解函數(shù)的執(zhí)行過程。閉包的基本結(jié)構(gòu)因為閉包不允許外界直接訪問,所以只能間接訪問函數(shù)內(nèi)部的數(shù)據(jù),獲得函數(shù)內(nèi)部數(shù)據(jù)的使用權(quán)。 大名鼎鼎的作用域和閉包,面試經(jīng)常會問到。閉包(closure)是Javascript語言的一個難點,也是它的特色。 聲明 理解閉包,先理解函數(shù)的執(zhí)行過程。 代碼在執(zhí)行的過程中會有一個預(yù)解析的過程,也就是在代碼的...

    WilsonLiu95 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<