ES6之var、let、const

Alan丶發表於2019-03-21

更多前端文章

1、變數提升

概述:變數可在宣告之前使用。

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 規定 let 和 const 命令不發生變數提升,使用 let 和 const 命令宣告變數之前,該變數是不可用的。主要是為了減少執行時錯誤,防止變數宣告前就使用這個變數,從而導致意料之外的行為。

2、暫時性死區

概述:如果在程式碼塊中存在 let 或 const 命令,這個區塊對這些命令宣告的變數,從一開始就形成了封閉作用域。凡是在宣告之前就使用這些變數,就會報錯。

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

剖析暫時性死區的原理,其實let/const同樣也有提升的作用,但是和var的區別在於

  • var在建立時就被初始化,並且賦值為undefined
  • let/const在進入塊級作用域後,會因為提升的原因先建立,但不會被初始化,直到宣告語句執行的時候才被初始化,初始化的時候如果使用let宣告的變數沒有賦值,則會預設賦值為undefined,而const必須在初始化的時候賦值。而建立到初始化之間的程式碼片段就形成了暫時性死區

3、不允許重複宣告

let不允許在相同作用域內,重複宣告同一個變數。

// 報錯
function func() {
  let a = 10;
  var a = 1;
}

// 報錯
function func() {
  let a = 10;
  let a = 1;
}
function func(arg) {
  let arg;
}
func() // 報錯

function func(arg) {
  {
    let arg;
  }
}
func() // 不報錯
複製程式碼

4、塊級作用域

在es5中我們會遇到下面這寫情況 第一種場景,內層變數可能會覆蓋外層變數。

var tmp = new Date();
function f() {
  console.log(tmp);
  if (false) {
    var tmp = 'hello world';//沒有塊級作用域tmp變數提升到函式作用域裡導致tmp為undefined
  }
}
f(); // undefined
複製程式碼

第二種場景,用來計數的迴圈變數洩露為全域性變數。

var s = 'hello';
for (var i = 0; i < s.length; i++) {
  console.log(s[i]);
}
console.log(i); // 5
複製程式碼

上面程式碼中,變數i只用來控制迴圈,但是迴圈結束後,它並沒有消失,洩露成了全域性變數。

  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5
}
複製程式碼

let實際上為 JavaScript 新增了塊級作用域。

5、const注意點

1、const宣告變數的時候必須賦值,否則會報錯,同樣使用const宣告的變數被修改了也會報錯 2、const宣告變數不能改變,如果宣告的是一個引用型別,則不能改變它的記憶體地址

const c ; //Uncaught SyntaxError: Missing initializer in const declaration
const a= {a:1};
a.a=2;
a={d:2};// Uncaught TypeError: Assignment to constant variable.
複製程式碼

本質:const實際上保證的,並不是變數的值不得改動,而是變數指向的那個記憶體地址所儲存的資料不得改動。對於簡單型別的資料(數值、字串、布林值),值就儲存在變數指向的那個記憶體地址,因此等同於常量。但對於複合型別的資料(主要是物件和陣列),變數指向的記憶體地址,儲存的只是一個指向實際資料的指標,const只能保證這個指標是固定的(即總是指向另一個固定的地址),至於它指向的資料結構是不是可變的,就完全不能控制了

那麼我們想得到不可修改的const要怎麼做呢?應該使用Object.freeze方法。

const foo = Object.freeze({});

// 常規模式時,下面一行不起作用;
// 嚴格模式時,該行會報錯
foo.prop = 123;
// 除了將物件本身凍結,物件的屬性也應該凍結。
var constantize = (obj) => {
  Object.freeze(obj);
  Object.keys(obj).forEach( (key, i) => {
    if ( typeof obj[key] === 'object' ) {
      constantize( obj[key] );
    }
  });
};
複製程式碼

參考文章 ECMAScript 6 入門

相關文章