天天看點

JavaScript中的詞法作用域(也叫 靜态作用域)、動态作用域、函數作用域和塊級作用域靜态作用域:動态作用域:函數作用域塊級作用域

靜态作用域:

一段代碼,在它執行之前就已經确定了它的作用域,

簡單來說就是在執行之前就确定了其可以應用哪些地方的作用域(意指:該作用域下的變量)。

以下例子為《JavaScript權威指南》中經典的一個例子:

例一:

var scope = "global scope";

function checkScope() {
	var scope = "local scope";

	function fn() {
		return scope;
	}
	return fn();
}
checkScope(); // local scope
           

分析:

在函數checkScope中定義了函數fn,并将函數fn的傳回值當作函數checkScope的傳回值傳回。

首先在函數fn的内部作用域中找變量scope,沒找到變量,是以在函數fn目前所在的作用域下找變量scope,找到變量,直接傳回,是以傳回的結果是local scope。

例二:

var scope = "global scope";

function checkScope() {
	var scope = "local scope";

	function fn() {
		return scope;
	}
	return fn;
}
checkScope()(); // local scope
           

分析:

在函數checkScope中調用函數fn,函數fn同作用域下定義了變量scope,是以輸出的是local scope。

在函數checkScope中定義了函數fn,并将函數fn當作函數checkScope的傳回值傳回,此時函數checkScope傳回的是一個函數對象,不管這個傳回的函數在哪裡執行,當他定義時,他的作用域就已經确定了。

是以首先在函數fn的内部作用域中找變量scope,沒找到變量,是以在函數fn目前所在的作用域下找變量scope,找到變量,直接傳回,是以傳回的結果還是local scope。

修改詞法作用域(不推薦)

      在代碼書寫時,作用域(詞法作用域)就已經确定了,但是可不可以再修改呢?

      通過eval和with都可以用來修改詞法作用域。

動态作用域:

函數的作用域是在函數調用的時候才決定的

在調用某個變量時,會從目前作用域逐級向上查找。

如果在目前作用域找到,就調用該變量,如果沒找到,就繼續向父級作用域查找,以此類推。

如果一直查找到最外層的全局作用域,都沒有找到該變量,那麼就表明沒有該變量。

注意差別于作用域鍊:函數在定義時,不光确定了它内部的作用域,還确定了它外部的作用域,也就是作用域鍊。
// 父級作用域變量num1
var num1 = 1;

function fn() {
	// 目前作用域變量num2
	var num2 = 2;

	// 在目前作用域沒有找到變量num1,向父級作用域查找,在父級作用域找到變量num1,直接調用
	console.log(num1); // 1
	// 在目前作用域找到變量num2,直接調用
	console.log(num2); // 2
	// 在目前作用域沒有找到變量num3,向父級作用域查找,在父級全局作用域也沒找到變量num3,證明該變量未定義
	console.log(num3); // ReferenceError: num3 is not defined
}
fn();
           

函數作用域

函數作用域的含義:屬于這個函數的全部變量可以在整個函數的範圍内使用及複用。

塊級作用域

{

    let a = '塊級作用域'

}
console.log(a);   //undefined
           

1.with

with也是塊作用域的一個例子。

2.try/catch

try/catch的catch分句也會建立一個塊作用域,其中聲明的變量僅在catch内部有效。

3.let

let關鍵字可以将變量綁定到所在的任意作用域中,換句話說,let為其聲明的變量隐式地劫持了所在的塊作用域。

用let将變量附加在一個已經存在的塊作用域的行為是隐式的。如果沒有密切關注哪些塊作用域中有綁定的變量,并且習慣性移動這些塊或者包含在其他塊中,就會導緻代碼混亂。

但是,用let進行的聲明不會在塊作用域中進行提升。聲明的代碼被運作之前,聲明并不存在。

4.垃圾收集

5.let循環

for循環頭部的let不僅将i綁定到for循環的塊中,事實上它将重新綁定到了循環的每一個疊代中,確定使用上一個循環疊代結束時的值重新進行指派。

for(let i=0;i<10;i++){

console.log(i);

}

console.log(i);
           

6.const

ES6引入了const,同樣可以用來建立塊作用域變量,但是其值是固定的。之後試圖修改值的操作都會引起錯誤。    

繼續閱讀