定義在函數體外的都屬於全域變量,定義在函數體內的屬於局部變數。這裡的定義是指透過var聲明的。
JavaScript有隱含的全域概念,表示你不宣告的任何變數都會成為一個全域物件屬性。例如:
function test(){ myname = "huming"; alert(myname); } test(); // "huming" alert(myname); //"huming"
兩個結果是一樣的,說明myname是一個全域變數。
那麼,隱式全域變數和明確定義的全域變數有沒有差別呢。 。答案肯定是有的,看下面的例子:
// 定义三个全局变量 var global_test1 = 1; global_test2 = 2; // 反面教材 (function () { global_test3 = 3; // 反面教材 }()); // 试图删除 delete global_test1; // false delete global_test2; // true delete global_test3; // true // 测试该删除 alert(typeof global_test1); // "number" alert(typeof global_test2); // "undefined" alert(typeof global_test3); // "undefined"
由上面的例子可以看出:在函數之外透過var定義的global_test1不能被刪除,而沒有經過var定義的global_test2和global_test3都被刪除了(無論是否是在函數體內建立)。
總結來說,在函數體外透過var宣告的全域變數不能被刪除,而隱式全域變數是可以刪除的。
這裡要注意了:JavaScript有一個行為叫做「hoisting」(懸置/置頂解析/預解析)。
我們透過一個例子來說明:
var myname = "huming"; //声明全局变量 function test() { alert(myname); var myname = "local_huming"; alert(myname); } test();
你猜兩次alert的內容一致嗎? ?顯然不一致,一致還用說嗎。 。實際輸出為:"undefined", "local_huming"。
上面的例子等同於
var myname = "huming"; //声明全局变量 function test() { var myname; alert(maname);<br> myname = "local_huming"; alert(myname); // "local" } test();
第一次alert輸出的myname並不是你以為的全域變量,而是和它在一個作用域(一個函數體)內的局部變量。雖然它還沒有被聲明,但被當作是聲明了。這就是所謂的「hoisting」。
這樣應該就明白了吧。當你在函數體中使用了一個變量,又在之後重新宣告的話,就可能產生錯誤。
書寫規格:
function test() { var a = 1, b = 2, c = a + b, d = {}, e, f; // function body... }
好處在於:
1、所有局部變數都定義在函數開始,方便查找;
2、防止變數在定義之前使用的邏輯錯誤。
如何替換?
在如何提升JavaScript效能這個問題上,大家最常聽到的建議應該就是盡量使用局部變數(local variables)來取代全域變數(global variables)。在我從事網路開發工作的九年時間裡,這條建議始終縈繞在我的耳邊,並且從來沒有質疑過,而這條建議的基礎,則來自於JavaScript處理作用域(scoping)和標識符解析(identifier resolution)的方法。
首先我們要明確,函數在JavaScript中具體表現為對象,創造一個函數的過程,其實也就是創造一個物件的過程。每個函數物件都有一個叫做 [[Scope]]的內部屬性,這個內部屬性包含建立函數時的作用域資訊。實際上,[[Scope]]屬性對應的是一個物件(Variable Objects)列表,列表中的物件是可以從函數內部存取的。比如說我們建立一個全域函數A,那麼A的[[Scope]]內部屬性中只包含一個全域物件(Global Object),而如果我們在A中建立一個新的函數B,那麼B的[[Scope] ]屬性中就包含兩個對象,函數A的Activation Object對像在前面,全域對象(Global Object)排在後面。
當一個函數被執行的時候,會自動建立一個可以執行的物件(Execution Object),並同時綁定一個作用域鏈(Scope Chain)。作用域鏈會透過下面兩個步驟來建立,用於進行標識符解析。
首先將函數物件[[Scope]]內部屬性中的對象,依序複製到作用域鏈中。
其次,在函數執行時,會建立一個新的Activation Object對象,這個物件中包含了this、參數(arguments)、局部變數(包括命名的參數)的定義,這個Activation Object對象會被置於作用域鏈的最前面。
在執行JavaScript程式碼的過程中,當遇到一個識別符,就會根據識別符的名稱,在執行上下文(Execution Context)的作用域鏈中進行搜尋。從作用域鏈的第一個物件(該函數的Activation Object物件)開始,如果沒有找到,就搜尋作用域鏈中的下一個對象,如此往復,直到找到了標識符的定義。如果在搜尋完作用域中的最後一個對象,也就是全域物件(Global Object)以後也沒有找到,則會拋出一個錯誤,提示使用者該變數未定義(undefined)。這是在ECMA-262標準中所描述的函數執行模型和標識符解析(Identifier Resolution)的過程,事實證明,大部分的JavaScript引擎確實也是這樣實現的。要注意的是,ECMA-262並沒有強制要求採用這種結構,只是對這部分功能加以描述而已。
以上是JavaScript變數宣告與局部變數取代全域變數用法詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!