1.做用域 函數
JavaScript的做用域與C、Java等語言不一樣,它不是以花括號包圍的塊級做用域,這個特性常常被大多數人忽視。例以下面代碼,在大多數類C的語言中會出現變量未定義的錯誤,但在JavaScript中卻徹底合法: spa
if (true) { var msg = 'msg'; } console.log(msg); // 輸出 msg;
這是由於JavaScript的做用域徹底是由函數來決定的,if、for語句中的花括號不是獨立的做用域。 code
2.函數做用域 ip
不一樣於大多數類C的語言,由一對花括號封閉的代碼塊就是一個做用域,JavaScript的做用域是經過函數來定義的,在一個函數中定義的變量只對這個函數內部可見,咱們稱爲函數做用域。在函數中引用一個變量時,JavaScript會先搜索當前函數做用域,若是沒有找到則搜索其上層做用域,一直到全局做用域。下面是一個簡單的例子: 作用域
var scope = 'global'; var f1 = function() { console.log(scope); } f1(); // 輸出 global var f2 = function() { var scope = 'f2'; console.log(scope); } f2(); // 輸出 f2
以上示例十分明瞭,JavaScript的函數定義是能夠嵌套的,每一層是一個做用域,變量搜索順序是從內到外,按照做用域搜索順序,在console.log函數訪問scope變量時,JavaScript會先搜索函數f2的做用域,恰巧在f2的做用域裏搜索到了scope變量,因此上層做用域中定義的scope就被屏蔽了。但下面這個例子可能就有些讓人困惑: io
var scope = 'global'; var f3 = function() { console.log(scope); var scope = 'f3'; } f3(); // 輸出 undefined
上面的代碼可能和你的預想不同,並無輸出global,而是undefined,這是爲何吶?這是JavaScript的一個特性,就是變量聲明語句永遠在該做用域裏最早被執行,因此上面的例子形同以下: console
var scope = 'global'; var f4 = function() { var scope; // 變量聲明最早被執行 console.log(scope); scope = 'f4'; //變量被賦予值 } f4(); // 輸出 undefined
這樣就不難理解運行f3()函數爲何沒輸出global,而是undefined了。 function
3.函數做用域的嵌套 class
一個做用域嵌套的例子: 變量
var f5 = function() { var scope = 'first'; (function() { var scope = 'second'; (function() { console.log(scope); }()); }()); } f5(); // 輸出 second
咱們在最內層函數中引用到了scope變量,經過做用域搜索,找到了其父做用域中定義的scope變量。
有一點要注意:函數做用域的嵌套關係是在定義時決定的,而不是在調用時決定的,下面是一個簡單的例子:
var scope = 'global'; var f6 = function() { console.log(scope); } var f7 = function() { var scope = 'f7'; f6(); } f7(); // 輸出 global
這個例子中,經過f7調用的f6在搜索scope時,找到的是f6函數的父做用域中定義的scope變量,而不是f7中定義的scope變量。這說明了函數做用域的嵌套關係是在定義時決定的,而不是在調用時決定的。