淺談var、let和const區別

前言:隨着2015年6月 ECMAScript 6.0 發佈以來,有幾個新的變量聲明方式進入前端開發者的視線,即 let、const、import 和 class 命令,而這些新的聲明方式之中有兩個容易和 var 混淆,那就是 let 和 const。那這兩個新的聲明方式和咱們以前使用的 var 聲明方式有什麼不一樣呢,那麼是什麼緣由致使 ES6 推崇新的聲明方式摒棄傳統的聲明方式呢,讓咱們經過這篇文章一探究竟。javascript

簡單介紹:

let 的用法相似於 var,可是 let 只在所在的代碼塊內有效,因此咱們通常使用 let 替代 var。而 const 用來聲明常量。前端

讓咱們先看一看這張表:java

聲明方式 變量提高 暫時性死區 重複聲明 初始值 做用域
var 容許 不存在 容許 不須要 除塊級
let 不容許 存在 不容許 不須要 塊級
const 不容許 存在 不容許 須要 塊級

接下來咱們根據這幾個方面來介紹 var、let和const的區別:變量提高、暫時性死區、重複聲明、初始值和做用域。es6

1、變量提高

概述:變量可在聲明以前使用。bash

首先看這三段代碼:函數

console.log(a);//正常運行,控制檯輸出 undefined
var a = 1;
複製代碼
console.log(b);//報錯,Uncaught ReferenceError: b is not defined
let b = 1;
複製代碼
console.log(c);//報錯,Uncaught ReferenceError: c is not defined
const c = 1;
複製代碼

var 命令常常會發生變量提高現象,按照通常邏輯,變量應該在聲明以後使用纔對。爲了糾正這個現象,ES6 規定 letconst 命令不發生變量提高,使用 letconst 命令聲明變量以前,該變量是不可用的。主要是爲了減小運行時錯誤,防止變量聲明前就使用這個變量,從而致使意料以外的行爲。學習

2、暫時性死區

概述:若是在代碼塊中存在 letconst 命令,這個區塊對這些命令聲明的變量,從一開始就造成了封閉做用域。凡是在聲明以前就使用這些變量,就會報錯。ui

var tmp = 123;

if (true) {
	tmp = 'abc';//報錯,Uncaught ReferenceError: tmp is not defined
	let tmp;
}
複製代碼

這段代碼的原意是在 if 內定義外部的 tmp 爲 'abc'。spa

但現實是,存在全局變量 tmp,可是塊級做用域內 let 又聲明瞭一個 tmp變量,致使後者被綁定在這個塊級做用域中,因此在 let 聲明變量前,對 tmp 賦值就報錯了。code

3、重複聲明

概述:指在相同做用域內,重複聲明同一個變量。

letconst 命令聲明的變量不容許重複聲明:

function func(){
  let a = 10;
  const PI = 3.1415;
  
  var a = 1;// 報錯,Uncaught SyntaxError: Identifier 'a' has already been declared
  var PI = 3;// 報錯,Uncaught SyntaxError: Identifier 'PI' has already been declared
}
// 當調用func()時報錯,Uncaught SyntaxError: Identifier 'a' has already been declared
function func(){
  let a = 10;
  const PI = 3.1415;
  
  let a = 1;// 報錯,Uncaught SyntaxError: Identifier 'a' has already been declared
  const PI = 3;// 報錯,Uncaught SyntaxError: Identifier 'PI' has already been declared
}
複製代碼

var 是容許重複定義的,而這又會給咱們帶來什麼麻煩呢?

var i = 10;
for(var i = 0;i < 5;i++){
  console.log(i);
}
console.log(i);// 輸出 5
複製代碼

對於學習過靜態(類型)語言的人知道,這段代碼要是替換成 c 語言或其餘靜態語言,輸出的結果應該是 10。然而對於 javascript 來講,這段代碼的輸出結果是 5。由於 var 命令沒有塊級做用域,因此 for 循環括號內的變量 i 會覆蓋外層 i,並且 var 容許重複聲明,因此這段代碼中 i 被聲明瞭兩次,i 的最終結果就被 for 循環的 i 給覆蓋了。

4、初始值

因爲 const 聲明的是隻讀的常量,一旦聲明,就必須當即初始化,聲明以後值不能改變。

const PI = 3.1415;
PI = 3;// 報錯,Uncaught TypeError: Assignment to constant variable.
複製代碼

5、做用域

在 ES5 中只有全局做用域和函數做用域,沒有塊級做用域,這帶來不少不合理的場景。

第一種場景,內層變量可能會覆蓋外層變量。

var tmp = new Date();//處於全局做用域

function f() {
  console.log(tmp);//處於函數做用域
  if (false) {
    var tmp = 'hello world';
  }
}

f(); // undefined
複製代碼

上面代碼的原意是,if代碼塊的外部使用外層的tmp變量,內部使用內層的tmp變量。

然而現實是在這段代碼中,function 內部的2個 tmp 變量處在同一函數做用域,因爲變量提高,致使函數做用域中的 tmp 覆蓋全局做用域中的 tmp,因此,f()輸出結果爲undefined。

第二種場景,用來計數的循環變量泄露爲全局變量(前面在重複聲明中提到的):

var i = 10;
for(var i = 0;i < 5;i++){
  console.log(i);
}
console.log(i);// 輸出 5
複製代碼

上面代碼中,變量i只用來控制循環,可是循環結束後,它並無消失,泄露成了全局變量。

本文內容以阮一峯的《ECMAScript 6 入門》爲基礎進行總結,歡迎各位提出文章內容中有錯誤和疑惑的地方~

相關文章
相關標籤/搜索