JS變數提公升,函式宣告提公升及變數作用域的理解

2021-10-01 14:10:47 字數 1740 閱讀 5016

在一般情況下,js**都是自上而下執行的,對於同乙個變數,可以通過如下方式來修改:

var a = 1;

a = 2;

console.log(a) // 2

a = function(){};

console.log(a) // function(){};

console.log(a);

var a = 1;

console.log(b);

var b = function(){};

這個時候console.log()都會輸出undefined而不會報錯,這是為什麼呢?這裡就是變數提公升起到的作用。我們在用var或者函式宣告的方式定義乙個變數時,這個變數的定義會提公升到方法體的最頂端,即如下所示:

var a = undefined;

var b = undefined;

console.log(a)

// ..

console.log(b)

因此得出一條結論:

函式宣告和變數宣告總是會被直譯器悄悄地被"提公升"到方法體的最頂部。
值得注意的是,使用let,const定義變數的時候,並不會發生提公升,因為它存在區域性(塊)作用域的概念,會出現暫時性死區,所以在它們之前列印變數將報錯。這是es6中的語法~

直接剖出問題:

var a = 1;

function a()

console.log(a)

此時**會列印什麼呢?答案是會列印1。這個問題也是隱藏著乙個概念:函式宣告提公升的優先順序高於變數宣告的提公升。瀏覽器底層的實現過程是這樣的:當js解析器在遇到函式宣告時,會優先將其提公升到定義體頂部,其次再是var宣告的變數,這樣就導致函式a被變數a給覆蓋的情況,所以最終將列印1。

作用域就是變數和函式的可訪問範圍,當**在乙個環境中執行時,會建立變數物件的乙個作用域鏈(scope chain),來保證對執行環境有權訪問的變數和函式的順序訪問。

作用域第乙個物件始終是當前執行**所在環境的變數物件。然後會一層層向外查詢,直到發現第乙個指定的變數為止。

例子:

var a = ;

function b(a);

return a

}var a1 = b(a);

console.log(a, a1)

附上一道面試題,上面**列印的是什麼呢?

這塊主要還是函式內部作用域和引用型別的乙個問題。具體過程如下:

(1)根據之前介紹的作用域和作用域鏈的概念可以知道,在函式體內,變數會就近查詢,而函式引數會存在於函式體內部作用域中,所以當我們把全域性變數a當作入參傳遞給函式時,又由於全域性a是引用型別,此時只是引用了它的位址,那麼我們通過a.age設定屬性時,全域性a也會改變。 (2)第二步是將a賦予了乙個新的值,此時的a根據就近查詢其實是引數a,本質上是將引數a賦予了乙個新的物件,這個時候和全域性變數的a沒有任何關係了,此時函式最後會返回乙個新的物件。

綜上兩步分析,列印a時輸出的是,列印a1會輸出了。

JS變數宣告提公升

js的變數作用域是離它最近的封閉語塊或 塊,包含他們內部的函式.在 塊中宣告會被隱式的提公升到封閉函式的頂部 1 function 6 var y 1 7 上面的 會被js解釋成下面的格式 1 function 8 有時候我們會不小心的在函式內部重新宣告了已有的變數 function text x ...

變數宣告提公升 Vs 函式宣告提公升

先看以下 1 var in window a in window console.log in window 2 var in window a in window console.log in window if a in window 3 var a var in window a in win...

JS變數宣告和函式宣告提公升

很多時候,在直覺上,我們都會認為js 在執行時都是自上而下一行一行執行的,但是實際上,有一種情況會導致這個假設是錯誤的。a 2 var a console.log a 按照傳統眼光,console.log a 輸出的應該是undefined,因為var a在a 2之後。但是,輸出的是2。再看第二段 ...