JavaScript作用域和變量提升

1.變量作用域

作用域:就是變量聲明的區域,也是變量和函數的可訪問範圍。在全局聲明的變量爲全局可見可訪問的就是全局變量,如果在函數內部聲明的變量只能在函數內部可訪問,可稱爲局部變量。

幾個注意點:
1.JavaScript中沒有塊級作用域(在ES5和ES6之前),只有函數作用域和全局作用域。for循環內部定義的變量是函數級別的作用域。
2.變量沒有在函數內聲明或者聲明的時候沒有帶var就是全局變量,擁有全局作用域。特殊:var a = b = c = 0;  b與c是全局變量

3.變量的作用域是以它聲明時爲準的,因爲變量的作用域在js代碼的解析階段就已經完成規則的制定。

簡單案例:
	//變量的作用域
	var t = 90;  //全局作用域,在js代碼中任何一個地方都可以訪問

	function f1(){  //f1函數 在全局作用域中

		var t2 = 10;  //t2是f1函數內部變量,只有在f1內可訪問
		console.log(t2);

		function f2(){ //f2函數  在f1函數的作用域中
			var t3 = 20;//只能在f2函數內部才能訪問
			console.log(t3);
			return t2*t3;  // 訪問了父級作用域中的t3
		}
		return f2();

	}
	var m = f1();

	console.log(m);

2.沒有塊級作用域

前面我說到JavaScript中沒有塊級作用域,這是對於es5 es6之前來說9(let const等)。for循環,while循環中定義的變量的作用域是函數級別的作用域。

例如:
	//沒有塊級作用域
	function f1(){
		for(var i=0;i<10;i++){//i變量是在for中定義的
			console.log(i);//打印1-9
		}
		console.log(i);//可以訪問到i變量  打印10   而在c++ Java等語言中是不行的
	}

	f1();


3.變量提升 (hositing)

js引擎在執行js代碼的時候,首先會先創建全局的EC(上下文)和函數的EC(如果有函數),在創建EC的時候已經把當前作

用域裏面聲明的變量初始化爲undefined,怎麼初始化呢?js引擎首先會在當前作用域去找var這個變量定義,發現有這個定義,那麼就

把它提升到作用域的最前面,並且保存在內存中(即EC中的變量對象VO),設爲undefined。

案例:
	var a = 10;

	function f1(){
		//在這裏首先會創建f1的執行上下文  並把裏面的變量初始化爲undefined
		console.log(a);  //代碼執行到這裏的時候, js引擎會去當前作用域內存中問有沒有這個變量的聲明,發現有,那麼就給他初始的undefined

		//假如說下面沒有var變量進行定義a,那麼js就會向父級作用域中去找這個變量,直到找到爲止

		var a = 19;  //在這裏給a賦值了19

		console.log(a); // 打印了19
	}

	f1();

	console.log(a);  //這裏無疑是10 沒什麼問題

所以,js引擎在創建上下文的時候,就會對有需要的變量進行變量提升,可以說是一種安全保護機制,ES6中對其進行了詳細討論。


注意:當變量聲明和函數聲明 爲同一個名字的時候,函數的優先級高。

	console.log(b); //打印b(){}

	var b = 9;

	function b(){

	}

	console.log(b); //打印9

由於函數被提升到最前面,那麼一開始打印的無疑是b(){} ,因爲js是動態語言,把b重新賦值爲9,覆蓋掉之前的function。


案例一:

	if ("a" in window) {
		var a = 1;
	}
	console.log(a);

首先看到你段代碼,你的答案是什麼?會不會是Uncaught ReferenceError: a is not defined?

告訴你,答案是1

首先,你要清楚var a = 1其實是定義了一個全局變量(屬於window對象下的屬性),因爲if並不是塊作用域,JavaScript中es5之前沒有塊作用域。所以這個條件判斷是成立的。

再來看:

	if (!("a" in window)) {
		var a = 1;
	}
	console.log(a);

那麼這個應該是什麼呢?答案是undefined,因爲條件不成立,沒有給a賦值成功,默認爲undefined  


案例二:

	fun();

	console.log(a);
	console.log(b);
	console.log(c);

	function fun(){
		var a = b = c = 10;
		console.log("fun中的a="+a);
		console.log("fun中的b="+b);
		console.log("fun中的c="+c);
	}

你得答案是什麼?

答案是:

由於a沒有定義,所以直接報錯,下面的兩行代碼被阻止執行了,假如把外面的console.log(a)註釋掉呢?

	fun();

	//console.log(a);
	console.log(b);
	console.log(c);

	function fun(){
		var a = b = c = 10;
		console.log("fun中的a="+a);
		console.log("fun中的b="+b);
		console.log("fun中的c="+c);
	}


輸出的是:



爲什麼外面b c都會是10呢? 原因就是var a = b = c = 10 ;其中b c就是全局變量,如果你想定義三個內部變量,那麼應該這樣定義:

var a = 10 ,b = 10, c = 10; 


弄懂了以上這些區別,基本上變量提升就沒什麼大問題了。

發佈了71 篇原創文章 · 獲贊 72 · 訪問量 48萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章