ES6系列入門學習記錄:let和const

ExplorerCl發表於2019-01-27

前言

感謝你能點進這篇文章,首先我先做一個說明,我是今年剛畢業的前端應屆生,這篇文章是我學習ES6的letconst部分之後,自己做的歸納筆記,也是我的第一篇文章。第一次做這種文章類的分享,而且是在一個大平臺上,如果有不足,希望可以幫我點出,十分感謝。

其實在發表文章之前,我們公司前端組的大佬就一直鼓勵我去做文章分享,打造自己的一個品牌。但是由於自己性格問題和懶惰,一直在拖。畢竟我最開始並不覺得自己有什麼能分享的,但是後續慢慢的才理解到一個真理:分享是沒有門檻的。所以開始嘗試做這種事情,希望可以慢慢做好,畢竟也是對自己的一種提升和鍛鍊。之後會繼續更新ES6的學習記錄文章,文章的內容,都是通過自己理解之後,然後用自己的話語去進行一個描述,當中可能會有不太準確或者不太恰當的描述,也歡迎觀看文章的您提出這類的意見和建議。同時我的文章會進行一些內容的驗證,有些部分可能會驗證的有點多,也請多擔待。

最後補充一句,我目前ES6系列學習的主要文獻是阮一峰大神的《ECMAScript 6 入門》

那就正式開始吧。

Let命令

let命令用於宣告變數,用法類似於var,但是let命令有個特點那就是隻會作用在let所在的作用域內。

Let命令的作用域

let a = 1;
{
    var b = 2;
    var c = a;
    let d = 3;
 }
 
 a // 1
 b // 2
 c // 1
 d // ReferenceError: b is not defined
複製程式碼

這裡的a引數的let命令用法毫無意義,如果這樣使用就和var沒區別,倒不如說要這樣使用還不如使用var

for迴圈則非常適合使用該命令

for(let i=0;i<1;i++){
   console.log('A',i);
}
console.log('B',i);

// A 0 
// ReferenceError: i is not defined
複製程式碼

for迴圈中使用let命令,每一輪迴圈的i都是一個新的變數,如果在內部使用計算公式等,則會通過JavaScript引擎記住上一輪迴圈結果的值,然後對其進行後續的迴圈計算,總而完成計算。

for(let i = 0;i<3;i++){
  let i = 'a';
  console.log(i);
}

// a
// a
// a
複製程式碼

此處是在for迴圈中使用let時候的一個特點,當子作用域中使用let再次定義了一個與父作用域中相同名稱的引數時,兩個引數互不干擾。

暫時性死區

只要塊級作用域記憶體在let命令,它所宣告的變數就“繫結”這個區域,不再受外部的影響。

let a = 1;
let b = 1;
{
   let a = 2;
   b = 2;
   console.log('a1',a);
   console.log('b1',b);
}
console.log('a2',a);
console.log('b2',b);

// a1 2
// b1 2
// a2 1
// b2 2
複製程式碼

當分別在父作用域子作用域內使用let定義引數時,即便引數名相同,他們也不是同一個引數。父作用域中定義的引數,只會作用在自身作用域未重新使用let命令定義同名引數的子作用域中。該情況就是自作用於中的let命令產生了暫時性死區。

var a = 1;
{
    console.log(a)
    let a = 2;
}

// ReferenceError: a is not defined
複製程式碼

以上程式碼可知,作用域內只要使用了let命令宣告的引數,即便有同名全域性變數,也無法在let命令程式碼執行之前對該引數進行任意操作,即使這個操作和let命令是屬於同一個作用域

let的暫時性死區的特點, 會導致任意作用域,只要某個引數有對應的let宣告,無論該宣告的位置在哪,該作用域內的該引數,便會完全獨立於在該作用域內,不會受到全域性或者父作用域中同名引數的干擾。

不允許重複宣告

注意一點,let命令是個小貪心鬼,同作用域內不允許有其他同名引數,無論是第二次同名命名是使用var還是let,都會報錯。其子作用域中,也必須使用let命令進行同名命名,否則也會報錯。

let a = 1;
let a = 2;
console.log(a);

// Identifier 'a' has already been declared
複製程式碼
var a = 1;
let a = 2;
console.log(a);

// Identifier 'a' has already been declared
複製程式碼
let a = 1;
var a = 2
console.log(a);

// Identifier 'a' has already been declared
複製程式碼
var a = 1;
var a = 2;
console.log(a);

//  2
複製程式碼
let a = 1;
{
	var a = 2;
	console.log(a);
}
console.log(a);
複製程式碼

以上程式碼若在chrome除錯皮膚測試時,請切記手動改引數名或者清除上一次程式碼所命名的引數。

Let命令不存在變數提升

所謂變數提升,就是變數可以在宣告程式碼之前使用,不會出現報錯,不過值未undefinedvar便有該特點。

console.log(a);
var a = 1;
// undefined

console.log(b);
let b = 1;
// Identifier 'b' has already been declared
複製程式碼

使用var命令宣告的引數,即會發生變數提升的引數,在指令碼開始執行時,對應的變數就已經被建立,直到執行到實際定義引數的程式碼時,該引數才會被賦上對應的值。

塊級作用域與函式宣告

概念

在ES5中,一般只有全域性作用域和函式作用域。

而在ES6中,增加了一個塊級作用域。ES6 規定,塊級作用域之中,函式宣告語句的行為類似於let,在塊級作用域之外不可引用。

一般而言,每個{}內部就是一個塊級作用域。

function f() { console.log('I am outside!'); }

(function () {
  if (false) {
    function f() { console.log('I am inside!'); }
  }

  f();}());
  
// Uncaught TypeError: f is not a function
複製程式碼

上述程式碼在ES6環境中執行的時候,會出現報錯,因為兩次宣告的function和執行的f()不在同一塊級作用域。

注意點

ES6改變了塊級作用域內宣告的函式的處理規則,但是由於網際網路目前的現狀是多個版本環境同時並行的情況。所以ES6有以下規定:

  • 允許在塊級作用域內宣告函式
  • 函式宣告類似於var,即會提升到全域性作用域或函式作用域的頭部。
  • 同時,函式宣告還會提升到所在的塊級作用域的頭部。

以上規則只對ES6的瀏覽器生效。在其他環境下不會生效。

綜上所述,我們需要儘量避免在塊級作用域內宣告函式。如果無法避免,也要寫成函式表示式。並且塊級作用域的宣告函式規則,必須在使用{}的情況下使用,不可以使用簡寫。

if(true) 
    function f() {}
//報錯
複製程式碼

const命令

概念

const用於宣告一個只讀的常量。

特點

由於const宣告的常量為只讀,所以其宣告的常量無法修改。

const a = 123;

 a //123
 
 a = 321; // TypeError: Assignment to constant variable.
複製程式碼

宣告的常量不能再次修改,所以意味著他必須在宣告的時候就進行賦值。因為如果不這樣做,你的宣告就沒有意義。

const a; // SyntaxError: Missing initializer in const declaration
複製程式碼

constlet相似,只在塊級作用域內生效,同時也不提升和存在暫時性死區。

if(true){
   const a = 1;
}

a // ReferenceError: a is not defined


if(true){
   console.log(b);
   const b = 1;
}
//ReferenceError: b is not defined
複製程式碼

同時也和let命令一樣,在同一塊級作用域內,不可重複使用一樣的名稱,即便一個是宣告常量,一個是宣告變數。

   var a = 1;
   let b = 1;
   
   const a = 2; // SyntaxError: Identifier 'a' has already been declared
   const b = 2; // SyntaxError: Identifier 'b' has already been declared
複製程式碼

本質

const並不是變數的值不可改變,而是變數所指向的那個記憶體地址所儲存的資料不得改變。特別是複合型別的資料,變數指向的記憶體地址,儲存的只是一個指向實際資料的指標,const只能保證指標是固定的。

聽起來其實有點繞,我個人的理解是,比如你需要調某個倉庫的貨物,然後我告訴你倉庫的地址,我只能保障那個倉庫的位置在那裡不變,但是倉庫裡面放什麼我就無法保證了。

const a = {};

a.prop = 1;
a.prop; // 1
複製程式碼

因此,使用const宣告的時候需要格外小心,不然就是紅紅的報錯了。(雖然快過年了,但是程式碼還是別增添顧念的氣氛了)

一些小補充

頂層物件的屬性

在ES5中,頂層物件的屬性和全域性變數是等價的,也就是說全域性變數的a = 1 等同於 window.a = 1

ES6中,為了改變這個情況,給varfunction命令保留了原有的這個特性的同時。也規定了letconstclass等命令所宣告的全域性變數,不屬於頂層物件的屬性。

var a = 1;
window.a //1

let b = a;
window.b //undefined
複製程式碼

總結

第一篇結束了,一開始寫的時候特別亂,然後慢慢調整成了目前這一篇。如果你覺得還可以,希望可以幫點個贊。之後的更新我會繼續奉上,也希望能受到你的喜歡和收到你的意見和建議,十分感謝。

相關文章