詳解JavaScript中的變數、範圍和提升

2020-10-14 18:00:15

變數是許多程式語言的基本組成部分,也是新手需要學習的第一個也是最重要的概念。JavaScript中有許多不同的變數屬性,以及命名變數時必須遵循的一些規則。在JavaScript中,有三個關鍵字用於宣告變數——var、let和const——每個關鍵字都會影響程式碼對變數的不同解釋。

本教學將介紹什麼是變數,如何宣告和命名變數,並進一步研究var、let和const之間的區別。我們還將回顧提升的影響以及全域性和區域性作用域對變數行為的重要性。

理解變數

變數是用於儲存值的命名容器。我們可能多次參照的一條資訊可以儲存在一個變數中,供以後使用或修改。在JavaScript中,變數中包含的值可以是任何JavaScript資料型別,包括數位、字串或物件。

在今天的JavaScript所基於的ECMAScript 2015 (ES6)語言規範之前,只有一種方法來宣告變數——使用var關鍵字。因此,大多數較老的程式碼和學習資源將只對變數使用var。我們將在下面單獨一節討論var、let和const關鍵字之間的區別。

我們可以使用var來演示變數本身的概念。在下面的範例中,我們將宣告一個變數,併為其賦值。

// Assign the string value Sammy to the username identifier
var username = "sammy_shark";

本宣告由以下幾部分組成:

  • 使用var關鍵字宣告變數

  • 變數名(或識別符號),使用者名稱

  • 賦值操作,由=語法表示

  • 分配的值「sammy_shark」

現在我們可以在程式碼中使用username。JavaScript將記住username表示字串值sammy_shark。

// Check if variable is equal to value
if (username === "sammy_shark") {
  console.log(true);
  }

輸出:

true

如前所述,變數可以用來表示任何JavaScript資料型別。在本例中,我們將使用字串、數位、物件、布林值和null值宣告變數。

// Assignment of various variables
var name = "Sammy";
var spartans = 300;
var kingdoms = [ "mammals", "birds", "fish" ];
var poem = { roses: "red", violets: "blue" }; 
var success = true;
var nothing = null;

使用console.log,我們可以看到特定變數中包含的值。

// Send spartans variable to the console
console.log(spartans);

輸出:300

變數將資料儲存在記憶體中,稍後可以存取和修改這些資料。變數也可以重新分配,並給定一個新值。下面的簡化範例演示瞭如何將密碼儲存到變數中,然後進行更新。

//為password變數賦值
var password = "hunter2";
//用一個新值重新分配變數值
password = "hunter3";
console.log(password);

輸出:

'hunter3'

在實際的程式中,密碼很可能安全地儲存在資料庫中。然而,這個例子說明了一種情況,在這種情況下,我們可能需要更新變數的值。password的值是hunter2,但是我們將其重新分配給了hunter3,這是JavaScript從那時起可以識別的值。

命名變數

變數名在JavaScript中稱為識別符號。我們討論了在理解JavaScript語法和程式碼結構時命名識別符號的一些規則,總結如下:

  • 變數名只能由字母(a-z)、數位(0-9)、美元符號($)和下劃線(_)組成

  • 變數名不能包含任何空白字元(製表符或空格)

  • 數位不能是任何變數的名稱開頭

  • 保留的關鍵字不能用作變數的名稱

  • 變數名區分大小寫

JavaScript還習慣在使用var或let宣告的函數和變數的名稱中使用駝峰大小寫(有時作為駝峰大小寫進行樣式化)。這是一種將第一個單詞小寫,然後將後面每個單詞的第一個字母大寫,中間沒有空格的做法。除了一些例外,大多數非常數的變數都遵循這種約定。使用const關鍵字宣告的常數變數的名稱通常都是大寫的。

這可能看起來像要學習很多規則,但很快就會成為編寫有效和常規變數名稱的第二天性。

var、let和const之間的區別

JavaScript有三個不同的關鍵字來宣告變數,這給語言增加了額外的複雜性。三者之間的區別是基於範圍、提升和重新分配。

關鍵字
範圍變數提升可以重新分配可以重新定義
var功能範圍YesYesYes
let阻止範圍NoYesNo
const阻止範圍NoNoNo

您可能想知道應該在自己的程式中使用這三種方法中的哪一種。一個普遍接受的做法是儘可能多地使用const,並在迴圈和重新分配的情況下使用let。通常,在處理遺留程式碼之外可以避免var。

變數作用域

JavaScript中的作用域是指程式碼的當前上下文,它決定了變數對JavaScript的可存取性。範圍的兩種型別是區域性的和全域性的:

  • 全域性變數是在塊之外宣告的變數

  • 區域性變數是在塊內宣告的變數

在下面的範例中,我們將建立一個全域性變數。

//初始化一個全域性變數
var creature = "wolf";

我們知道變數可以重新分配。使用區域性作用域,我們實際上可以建立與外部作用域中的變數同名的新變數,而無需更改或重新分配原始值。

在下面的範例中,我們將建立一個全域性species變數。函數內部是一個具有相同名稱的區域性變數。通過將它們傳送到控制檯,我們可以看到變數的值如何根據範圍而不同,並且原始值不會更改。

//初始化一個全域性變數
var species = "human";
function transform() {
//初始化一個區域性的、函數作用域的變數
  var species = "werewolf";
  console.log(species);
}
//記錄全域性和區域性變數
console.log(species);
transform();
console.log(species);

輸出:

human
werewolf
human

在本例中,區域性變數是函數作用域的。使用var關鍵字宣告的變數總是函數作用域,這意味著它們將函數識別為具有獨立作用域。因此,這個區域性作用域的變數不能從全域性作用域存取。

然而,新的關鍵字let和const是塊範圍的。這意味著從任何型別的塊(包括函數塊、if語句、for和while迴圈)建立一個新的本地範圍。

為了說明函數作用域變數和塊作用域變數之間的區別,我們將使用let在if塊中分配一個新變數。

var fullMoon = true;
//初始化一個全域性變數
let species = "human";
if (fullMoon) { 
//初始化一個塊範圍的變數
  let species = "werewolf";
  console.log(`It is a full moon. Lupin is currently a ${species}.`);
}
console.log(`It is not a full moon. Lupin is currently a ${species}.`);

輸出:

It is a full moon. Lupin is currently a werewolf.
It is not a full moon. Lupin is currently a human.

在此範例中,species變數具有一個值global(human),另一個值local(werewolf)。var但是,如果我們使用,則會有不同的結果。

//使用var初始化一個變數
var species = "human";
if (fullMoon) {  
//嘗試在一個塊中建立一個新變數
  var species = "werewolf";
  console.log(`It is a full moon. Lupin is currently a ${species}.`);
}

console.log(`It is not a full moon. Lupin is currently a ${species}.`);

輸出:

It is a full moon. Lupin is currently a werewolf.
It is not a full moon. Lupin is currently a werewolf.

在這個例子的結果中,全域性變數和塊範圍的變數都以相同的值結束。這是因為您不是使用var建立一個新的本地變數,而是在相同的範圍內重新分配相同的變數。var不能識別是否屬於不同的新範圍。通常建議宣告塊範圍的變數,因為它們生成的程式碼不太可能無意中覆蓋變數值。

變數提升

到目前為止,在大多數範例中,我們已經使用var宣告了一個變數,並使用一個值初始化了它。在宣告和初始化之後,我們可以存取或重新分配變數。

如果我們試圖在變數被宣告和初始化之前使用它,它將返回undefined。

//在宣告變數之前嘗試使用它
console.log(x);
/ /變數賦值
var x = 100;

輸出:

undefined

但是,如果省略var關鍵字,就不再宣告變數,而是初始化它。它將返回一個ReferenceError並停止指令碼的執行。

//在宣告變數之前嘗試使用它
console.log(x);
//沒有var的變數賦值
x = 100;

輸出:

ReferenceError: x is not defined

原因在於提升,這是JavaScript的一種行為,其中變數和函數宣告被移到它們作用域的頂部。由於只掛起實際宣告,而沒有初始化,因此第一個範例中的值返回未定義的值。

為了更清楚地演示這個概念,下面是我們編寫的程式碼以及JavaScript如何解釋它。

// The code we wrote
console.log(x);
var x = 100;
// How JavaScript interpreted it
var x;
console.log(x);
x = 100;

JavaScript在執行指令碼之前將x儲存為記憶體作為變數。 由於它在定義之前仍然被呼叫,因此結果是未定義的而不是100.但是,它不會導致ReferenceError並停止指令碼。

儘管var關鍵字實際上並未更改var的位置,但這有助於表示提升的工作原理。 但是,這種行為可能會導致問題,因為編寫此程式碼的程式設計師可能希望x的輸出為true,而不是undefined。

在下一個例子中,我們還可以看到提升是如何導致不可預測的結果的:

//在全域性範圍內初始化x
var x = 100;
function hoist() {
//不應影響編碼結果的條件
  if (false) {
      var x = 200;
  }
  console.log(x);
}

hoist();

輸出:

undefined

在本例中,我們宣告x全域性為100。根據if語句,x可以更改為200,但是由於條件為false,所以它不應該影響x的值。

這種不可預測的行為可能會在程式中引起bug。由於let和const是塊範圍的,所以它們不會以這種方式提升,如下所示。

//在全域性範圍內初始化x
let x = true;function hoist() {
//在函數作用域中初始化x
 if (3 === 4) {
      let x = false;
  }
  console.log(x);
}

hoist();

輸出:

true

變數的重複宣告(這在var中是可能的)將在let和const中丟擲一個錯誤。

//試圖覆蓋用var宣告的變數
var x = 1;
var x = 2;

console.log(x);

輸出:2

//試圖覆蓋用let宣告的變數
let y = 1;
let y = 2;

console.log(y);

輸出:

Uncaught SyntaxError: Identifier 'y' has already been declared

總之,使用var引入的變數有可能受到提升的影響,提升是JavaScript中的一種機制,其中變數宣告被儲存到記憶體中。這可能導致程式碼中出現未定義的變數。let和const的引入解決了這個問題,它在試圖在宣告變數之前使用該變數或多次宣告該變數時丟擲一個錯誤。

常數

許多程式語言都有常數,這些常數是不能修改或更改的值。在JavaScript中,const識別符號是根據常數建模的,不能重新分配分配給const的值。

將所有const識別符號都寫成大寫是常見的約定。這將它們與其他變數值區分開來。

在下面的範例中,我們使用const關鍵字將變數SPECIES初始化為常數。試圖重新分配變數將導致錯誤。

//給const賦值
const SPECIES = "human"; 

//嘗試重新分配值
SPECIES = "werewolf";

console.log(SPECIES);

輸出:

Uncaught TypeError: Assignment to constant variable.

因為不能重新分配const值,所以需要同時宣告和初始化它們,否則也會丟擲錯誤。

//宣告,但不初始化const
const TODO;

console.log(TODO);

輸出:

Uncaught SyntaxError: Missing initializer in const declaration

不能在程式設計中更改的值稱為不可變值,而可以更改的值是可變的。雖然const值不能重新分配,但是它們是可變的,因為可以修改用const宣告的物件的屬性。

//建立一個具有兩個屬性的CAR物件
const CAR = {
    color: "blue",
    price: 15000}
//修改CAR的屬性
CAR.price = 20000;

console.log(CAR);

輸出:

{ color: 'blue', price: 20000 }

常數非常有用,可以讓將來的自己和其他程式設計師清楚地認識到,不應該重新分配預期的變數。如果您希望將來修改某個變數,那麼您可能希望使用let來宣告該變數。

相關免費學習推薦:

以上就是詳解JavaScript中的變數、範圍和提升的詳細內容,更多請關注TW511.COM其它相關文章!