ES6系列——let和const深刻理解

前言

在ES6中多了兩個變量定義的操做符——let和const,在如今項目中,ES6已是不可獲缺,我打算在掘金上整理一套ES6的系列,會收集經常使用的知識點,喜歡的能夠點個喜歡,關注,或者能夠去github點個starhtml

ES5沒有塊級做用域

你們都知道js是沒有塊級做用域的,咱們先了解一下塊級做用域。git

任何一對花括號中的語句集都屬於一個塊,在這之中定義的全部變量在代碼塊外都是不可見的es6

瞭解定義以後,咱們👀一個用爛了的例子:github

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

上面這個例子,最外面會輸出10。顯而易見,沒有塊級做用域。面試

ES5能夠怎麼建立塊級做用域

  • 當即執行函數

關於這一點咱們能夠看道面試題就能明白。segmentfault

var func = [];
for(var i = 0; i < 10; i++) {
  func.push(function(){
    console.log(i)
  });
}
func.forEach((func) => {
  func();
})
//10個10複製代碼

爲何會產生這樣的事情呢?由於在循環內部這些i都是用同一個詞法做用域的,換言之,這10個i用的都是最後的輸出的i,最後的i也就等於10。
而當即執行函數就不同,他用函數做用域代替塊級做用域,強制在循環內部建立副本,以便輸出1,2,3,4...安全

var func = [];
for(var i = 0; i < 10; i++) {
  func.push((function(value){
    return function() {
      console.log(value)
    }
  })(i));
}
func.forEach((func) => {
  func();
})
//會輸出1到9複製代碼

對當即執行函數有興趣的好能夠看看這麼幾篇博文,我在這裏就不用大篇幅贅述,咱們簡單過一下下面幾種方法,而後去將咱們今天的主角們。
推薦博文
推薦博文函數

  • try-catch

try-catch這個建立塊級做用域在紅皮書中有提到過,我沒用過,以爲這個知識點了解就能夠,也不經常使用。ui

try {
   throw 'myException';
}
catch (e) {
   console.log(e);
}
console.log(e);
//第一個輸出myException,第二個輸出e is not defined複製代碼

ES6中的塊級做用域

在ES6中提出了let和const,咱們能夠看一下下面這幾個例子,在每次循環中,let會建立一個詞法做用域,並與以前迭代中同名變量的值將其初始化。es5

for(let i = 0; i < 10; i++) {
      console.log(1);
    }
console.log(i);
//報錯i is not defined複製代碼
const func = [];
for(let i = 0; i < 10; i++) {
  func.push(function(){
    console.log(i)
  });
}
func.forEach((func) => {
  func();
})
//會輸出0到9複製代碼

這個特性一樣適用於for in

const funcs = [],
  obj = {
    a: 'lai',
    b: 'hua',
    c: 'min'
  };
for (let key in obj) {
  funcs.push(() => {
    console.log(key)
  })
}
funcs.forEach((func) => {
  func()
});
//輸出的是a b c複製代碼

不能重複聲明變量

在一個做用域中,已經用var、let、const聲明過某標識符以後,不能在用let、const聲明變量,否則會拋出錯誤

var a = 0;
let a = 10;
// 報錯複製代碼

可是在做用域中嵌套一個做用域就不會,看下面這個例子

var a = 0;
if (true) {
  let a = 10;
}
// 不會報錯複製代碼

const效果也是一致的,不過const用於定義常量,const還有如下特性

const聲明變量

當你用const聲明變量,不初始化的話,就會發生報錯

const a;
// 報錯複製代碼

而const的本質是聲明的,不容許修改綁定,可是容許修改值,因此大多數場景,咱們都用const來聲明對象,那樣對象的指針不會改變,相對來講安全,看一下下面的例子

const person = {
  name = 'laihuamin'
}
person.name = 'lai';
//到這裏不會發生報錯,只會改變值
person = {};
//這裏改變了對象的指針,因此會發生報錯複製代碼

而const不止能用於對象指針綁定,還能運用在for in的迭代中,由於每次迭代不會修改已有的綁定,而是會建立新的綁定。看下面的例子

const funcs = [],
  obj = {
    a: 'lai',
    b: 'hua',
    c: 'min'
  };
for (const key in obj) {
  funcs.push(() => {
    console.log(key)
  })
}
funcs.forEach((func) => {
  func()
});
//輸出a b c複製代碼

可是在循環中就不能用,循環會修改已有的綁定,而const定義的常量時不能修改綁定的,因此會報錯。

沒有變量提高

對於ES5的變量提高有一個經典的考題。以下:

var a = 10;
(function () {
  console.log(a);
  var a = 1;
})();
// 這個會輸出undefined複製代碼

其實這個很好理解,js做用域連是從內向外尋找變量的,那麼函數的做用域中有a這個變量,因爲var會發生變量提高,就至關於下面這個過程

var a;
console.log(a);
a = 1;複製代碼

因此,這個a變量就是undefined。而let和const就不同,把var換成let或者const都會報錯。

暫時性死區

咱們先來看例子,再來根據例子解析:

console.log(a);
let a = 10;
//Uncaught ReferenceError: a is not defined複製代碼

let和const定義的變量是存在暫時性死區的,而var沒有,咱們來了解一下兩個操做符的工做原理:
對於var而言,當進入var變量的做用域時,會當即爲他建立存儲空間,並對它進行初始化,賦值爲undefined,當函數加載到變量聲明語句時,會根據語句對變量賦值。
而let和const卻不同,當進入let變量的做用域時,會當即給他建立存儲空間,可是不會對他進行初始化,因此會拋出如上錯誤。

而對於typeof操做符來講,結果是一致的,同樣會報錯:

console.log(typeof a);
let a = 10;
//Uncaught SyntaxError: Identifier 'a' has already been declared複製代碼

因此最佳實踐是把聲明的變量所有提到做用域的開頭,這樣既方便管理,又能避免沒必要要的麻煩

全局變量綁定

var聲明全局變量的時候,當使用關鍵詞,那麼就會覆蓋掉window對象上本來擁有的屬性,咱們看一下下面這個例子:

var RegExp = 'lai';
console.log(window.RegExp);
var a = 'hua';
console.log(window.a);
var Array = 'min';
console.log(window.Array);
var b = new Array();
//lai
//hua
//min
//Uncaught TypeError: Array is not a constructor複製代碼

而換成let和const的時候就不會發生這樣的事情,咱們用一樣的例子來看一看:

let RegExp = 'lai';
console.log(window.RegExp);
let a = 'hua';
console.log(window.a);
let Array = 'min';
console.log(window.Array);
let b = new window.Array();
console.log(b);
//ƒ RegExp() { [native code] }
//undefined
//ƒ Array() { [native code] }
//[]複製代碼

結果和上面同樣,咱們更能夠進一步認證

let RegExp = 'lai';
console.log(RegExp === window.RegExp);
var Array = 'hua';
console.log(Array === window.Array);

//會輸出 false 和 true複製代碼

總結

根據以上講的,最佳實踐應該是,能用const定義對象的,不要用let,能用let定義變量的,不要用var。至於他的不少特性,瞭解了能更好的幫助你運用。若是以爲筆者寫的能夠的點一個喜歡,以後還會持續更新其餘板塊,但願能給筆者的github點個star,謝謝支持

相關文章
相關標籤/搜索