js變數作用域 變數提公升

2022-03-09 18:14:47 字數 2305 閱讀 5934

1、js作用域

在es5中,js只有兩種形式的作用域:全域性作用域和函式作用域,在es6中,新增了乙個塊級作用域(最近的大括號涵蓋的範圍),但是僅限於let方式申明的變數。

2、變數宣告

1

var x; //

變數宣告

2var x=1; //

變數宣告並賦值

3 x = 1; //

定義全域性變數並賦值

3、函式宣告

function fn(){};     //

函式宣告並定義

var fn = function(){}; //

實際上是定義了乙個區域性變數fn和乙個匿名函式,然後把這個匿名函式賦值給了fn

4、變數提公升

var tmp = new

date();

function

fn()

fn();

a情形

var tmp = new

date();

function

fn()

}fn();

b情形

var tmp = new

date();

function

fn()

}fn();

c情形從上面可以看到,b情形和c情形為什麼不同於a情形,就是因為變數提公升了(ps: c情形不同於b情形的是判斷條件為true,但是這裡不是看**有沒有被執行,是看變數有沒有被定義)。fn函式裡面定義了同名變數tmp,無論在函式的任何位置定義tmp變數,它都將被提公升到函式的最頂部。等同於下面情形:

var tmp = new

date();

console.log(tmp);

function

fn()

}fn();

這裡需要說明的是,雖然所有的申明(包括es5的var、function,和es6的function *、let、const、class)都會被提公升,但是var、function、function *和let、const、class的的提公升卻並不相同!具體原因可以看這裡的說明(大體的意思是雖然let,const,class也被提公升了,但是卻並不會被初始化,這時候去訪問他們則會報referenceerror異常,他們需要到語句執行的時候才會被初始化,而在被初始化之前的狀態叫做temporal dead zone)。

因為這樣的原因,推薦的做法是在申明變數的時候,將所用的變數都寫在作用域(全域性作用域或函式作用域)的最頂上,這樣**看起來就會更清晰,更容易看出來那個變數是來自函式作用域的,哪個又是來自作用域鏈。

5、重複宣告

var x = 1;

console.log(x);

if(true

)console.log(x);

上面的輸出其實是:1 2 2。雖然看起來裡面x申明了兩次,但上面說了,js的var變數只有全域性作用域和函式作用域兩種,且申明會被提公升,因此實際上x只會在最頂上開始的地方申明一次,var x=2的申明會被忽略,僅用於賦值。也就是說上面的**實際上跟下面是一致的:

var x = 1;

console.log(x);

if(true

)console.log(x);

6、函式和變數同時提公升的問題

console.log(fn);

function

fn(){};

var fn = 'string';

上面的輸出結果其實是:function fn(){},也就是函式內容。

console.log(fn);

var fn = function

fn(){};

var fn = 'string';

這時輸出結果就是undefined,知道上面的宣告提公升的道理就不難理解了。

總結:要徹底理解js的作用域和hoisting,只要記住以下三點即可:

1、所有申明都會被提公升到作用域的最頂上

2、同乙個變數申明只進行一次,並且因此其他申明都會被忽略

3、函式宣告的優先順序優於變數申明,且函式宣告會連帶定義一起被提公升

注意:

通過with語句,可以臨時改變執行期上下文的作用域鏈,此時的對非var定義的變數進行訪問,會首先訪問with中物件的屬性,然後才會向上順著作用域鏈向上檢查該屬性。

js的變數作用域 ,變數提公升

function 結果 undefined 10 等同於下面 var a undefined 定義全域性變數 function 分析 1.在產生乙個作用域的時候,會預編譯一次裡面的變數,其中的動作是將所有的變數名,函式名,提前定義,然後在賦予當前的變數的所在作用域,執行。2.變數名的定義會覆蓋函式名...

變數提公升 作用域

console.log a undefined console.log window.a undefined console.log a in window true 在變數提公升階段,在全域性作用域中宣告了乙個變數a,此時就已經把a當做屬性賦值給window了,只不過此時還沒有給a賦值,預設值un...

作用域與變數提公升

js中變數的作用域有全域性作用域和區域性作用域兩種,作用域簡單來講就是變數與函式的可訪問範圍。宣告提前是在js預編譯是就進行了,變數提公升知識提公升變數的宣告,並不會吧值也提上來。例1 var name one function test var name one function test 解析 ...