首頁  >  文章  >  web前端  >  JavaScript變數宣告與局部變數取代全域變數用法詳解

JavaScript變數宣告與局部變數取代全域變數用法詳解

伊谢尔伦
伊谢尔伦原創
2017-07-18 09:54:232297瀏覽

定義在函數體外的都屬於全域變量,定義在函數體內的屬於局部變數。這裡的定義是指透過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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn