變量作用域是程序中定義這個變量的區域。
先來看一段示例:
/* 代碼1 */
var scope = "global "; function checkScope() { var scope = "local "; function childCheck() { var scope = "childLocal "; document.write(scope); } function childUndefined() { document.write(scope); var scope; } function childOverride() { scope = "childOverride "; document.write(scope); } document.write(scope); //輸出"local" childCheck(); //輸出"childLocal" childUndefined(); //輸出"undefined" childOverride(); //輸出"childOverride" document.write(scope); //輸出"childOverride" } checkScope(); //輸出"local childLocal undefinedchildOverride childOverride" document.write(scope); //輸出"global "
全局作用域與局部作用域
全局(global)變量的作用域是全局的,在Javascript中處處有定義;而函數內部聲明的變量是局部(local)變量,其作用域是局部性的,只在函數體內部有定義。對於下面的輸出讀者應不會感到意外。
/* 代碼2 */
var scope = "global"; function checkScope() { var scope = "local"; document.write(scope); } checkScope(); //輸出"local" document.write(scope); //輸出"global"
全局變量作用域中使用變量可以不用var語句,但在聲明局部變量是一定要使用var語句,否則會視為對全局變量的引用。看下面代碼:
/* 代碼3 */
var scope = "global"; function checkScope() { scope = "local"; document.write(scope); } checkScope(); //輸出"local" document.write(scope); //輸出"local"
沒有塊作用域
Javascript沒有塊級作用域,函數中聲明的變量在整個函數中都是有定義的。對於下面的代碼對於生疏的讀者可能頗感意外:
/* 代碼4 */
var scope = "global"; function checkScope() { document.write(scope); //語句4.1 var scope = "local"; //語句4.2 document.write(scope); } checkScope(); //輸出"undefinedlocal"
由於語句4.1(var scope = "local";)聲明的變量在整個checkScope函數作用域內都有效,因此在語句4.2(document.write(scope); )執行的時scope引用的是局部變量,而此時局部變量scope尚未定義,所以輸出”undefined”。因此一個好的編程習慣是將所有的變量聲明集中起來放在函數的開頭。
在了解了上述內容之後,讀者再看看代碼1應該不會感到困惑了。
對象的屬性變量
對象的屬性變量比較容易理解,看一下下面的代碼讀者應該不會感到疑惑。
/* 代碼5 */
var scope = "global "; var obj = new Object(); obj.scope = "object "; obj.checkScope = function () { var scope = "loacl "; document.write(scope); //輸出"loacl" document.write(this.scope); //輸出"object" document.write(window.scope); //輸出"global" } obj.checkScope(); //輸出"loacl object global"
所謂作用域,就是說這個變量在代碼塊中的有效范圍。如果不理解 JavaScript 作用域,調試代碼的時候可能會比較困難。
在函數中,如果用var來聲明一個變量,那麼該變量的作用域就只限於該函數內部,函數外的代碼無法訪問該變量。如果在該函數中再聲明一個函數,那麼這個內部的函數也可以訪問這個變量。
反過來,如果聲明變量的時候沒有用var,那麼此變量的作用域就不局限於這個函數了。JavaScript 引擎會再全局范圍中檢查該變量是否被定義過。如果該變量沒有被定義過,那麼它就會被定義為一個全局變量。
函數可以訪問相同作用域中的變量:
var foo = 'hello'; var sayHello = function() { console.log(foo); }; sayHello(); // logs 'hello' console.log(foo); // also logs 'hello'
變量作用域之外的代碼不能訪問該變量:
var sayHello = function() { var foo = 'hello'; console.log(foo); }; sayHello(); // logs 'hello' console.log(foo); // doesn't log anything
不用作用域中名稱相同的變量,有不同的值:
var foo = 'world'; var sayHello = function() { var foo = 'hello'; console.log(foo); }; sayHello(); // logs 'hello' console.log(foo); // logs 'world'
函數定以後可以看到函數內變量值的改變:
var myFunction = function() { var foo = 'hello'; var myFn = function() { console.log(foo); }; foo = 'world'; return myFn; }; var f = myFunction(); f(); // logs 'world' -- haha
作用域也會穿越 — 閉包
// 一個自執行的匿名函數 (function() { var baz = 1; var bim = function() { alert(baz); }; bar = function() { alert(baz); }; })(); console.log(baz); // 在函數外面不能訪問 baz bar(); // 聲明 bar 的時候並沒有用 var // 所以 bar 是一個全局變量; 但是, // bar 和 baz 在相同的作用域內被定義, // 所以 bar 可以訪問 baz // 其實 bar 是個閉包函數 bim(); // bim 的作用域只限於匿名函數內部, // 所以這裡不能調用
綜合
所謂作用域,就是說這個變量在代碼塊中的有效范圍。如果不理解 JavaScript 作用域,調試代碼的時候可能會比較困難。
在函數中,如果用var來聲明一個變量,那麼該變量的作用域就只限於該函數內部,函數外的代碼無法訪問該變量。如果在該函數中再聲明一個函數,那麼這個內部的函數也可以訪問這個變量。
反過來,如果聲明變量的時候沒有用var,那麼此變量的作用域就不局限於這個函數了。JavaScript 引擎會再全局范圍中檢查該變量是否被定義過。如果該變量沒有被定義過,那麼它就會被定義為一個全局變量。
函數可以訪問相同作用域中的變量:
var foo = 'hello'; var sayHello = function() { console.log(foo); }; sayHello(); // logs 'hello' console.log(foo); // also logs 'hello'
變量作用域之外的代碼不能訪問該變量:
var sayHello = function() { var foo = 'hello'; console.log(foo); }; sayHello(); // logs 'hello' console.log(foo); // doesn't log anything
不用作用域中名稱相同的變量,有不同的值:
var foo = 'world'; var sayHello = function() { var foo = 'hello'; console.log(foo); }; sayHello(); // logs 'hello' console.log(foo); // logs 'world'
函數定以後可以看到函數內變量值的改變:
var myFunction = function() { var foo = 'hello'; var myFn = function() { console.log(foo); }; foo = 'world'; return myFn; }; var f = myFunction(); f(); // logs 'world' -- haha
作用域也會穿越 — 閉包
// 一個自執行的匿名函數 (function() { var baz = 1; var bim = function() { alert(baz); }; bar = function() { alert(baz); }; })(); console.log(baz); // 在函數外面不能訪問 baz bar(); // 聲明 bar 的時候並沒有用 var // 所以 bar 是一個全局變量; 但是, // bar 和 baz 在相同的作用域內被定義, // 所以 bar 可以訪問 baz // 其實 bar 是個閉包函數 bim(); // bim 的作用域只限於匿名函數內部, // 所以這裡不能調用