在一般情況下,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。再看第二段 ...