持續更新的github筆記,連接地址:Front-End-Basics html
此篇文章的筆記地址:字符到底發生了什麼變化 git
ES6走走看看系列,特別鳴謝奇舞讀書會~github
注意:ES6容許塊級做用域任意嵌套瀏覽器
{{{{{{let text = 'Hello World!'}}}}}}
由於有了塊級做用域,而後咱們纔有繼續往下聊的可能。安全
塊級聲明是用於聲明在指定塊的做用域以外沒法訪問的變量。函數
一、 聲明的變量具備塊級做用域的特性spa
// 例子 function getValue (condition) { if (condition) { let value = 'blue'; return value; } console.log(value) // 報錯 value is not defined } getValue()
二、 在同一個做用域內不能使用let聲明同名的變量code
// 不論是var,const或者let,新的let聲明以前同名的變量,都會報錯 var count = 30; let count = 40; // 報錯 Identifier 'count' has already been declared // 函數形參和函數內部的let聲明變量重名,報錯 function test(value) { let value = 3; } test() // 報錯 Identifier 'value' has already been declared // 在不一樣的做用域聲明的變量重名是沒問題的 let count = 30; if(true) { let count = 40; // 不一樣的做用域,不會報錯 }
三、 聲明沒有預解析,不存在變量提高,有「臨時死區」(TDZ)htm
從塊的開始到變量聲明這段的區域被稱爲臨時死區,ES6明確規定,若是區塊中存在let和const命令,則這個區塊對這些命令聲明的變量從一開始就造成封閉做用域,只要在聲明以前就使用這些變量(賦值,引用等等),就會報錯。對象
if(true) { console.log(typeof value); // 報錯 value is not defined let value = 'blue'; }
注意:TDZ是區域是「塊開始」到「變量聲明」,下面的例子不報錯
// typeof 說是相對安全,確實是,永遠拿不到想要的結果 console.log(typeof value); // 打印 undefined,沒有報錯 if(true) { let value = 'red'; }
一、 常量聲明的值是不可變的
注意:const聲明的對象不容許修改綁定,但能夠修改該對象的屬性值。
const number = 6; number = 5; // 報錯 Assignment to constant variable const obj = {number: 1}; obj.number = 2; // 不報錯 obj = {number: 3}; // 報錯 Assignment to constant variable
二、 由於常量聲明後值就不可更改了,因此聲明時必須賦值
// 有效的常量 const count = 30; // 報錯 Missing initializer in const declaration const name;
三、 聲明的常量具備塊級做用域的特性
if(true) { const number = 5; } console.log(number) // 報錯 number is not defined
四、 在同一個做用域內不能使用const聲明同名的變量
var message = 'Hello'; let age = 25; // 這兩條語句都會報錯 const message = 'Good'; const age = 30;
五、 聲明沒有預解析,不存在變量提高,有「臨時死區」(TDZ)
總結:一張表格
聲明方式 | 變量提高 | 做用域 | 是否須要初始值 | 重複定義 |
---|---|---|---|---|
var | 是 | 函數級 | 不須要 | 容許 |
let | 否 | 塊級 | 不須要 | 不容許 |
const | 否 | 塊級 | 須要 | 不容許 |
擴展:再提一下變量命名,不論是var、let、const聲明的變量名,能夠由數字,字母,下劃線及美圓符號組成,可是不能以數字開頭。美圓符號能夠放到任何一個位置,甚至單獨一個美圓符號。
循環中的let聲明
// 第一個對比 // before for(var i = 0; i < 5; i++) { // ... 省略一些代碼 } console.log(i) // 5 //after for(let i = 0; i < 5; i++) { // ... 省略一些代碼 } console.log(i) // 報錯 i is not defined // 第二個對比 // before var funcs = []; for(var i = 0; i < 10; i++) { funcs.push(() => {console.log(i)}) } funcs.forEach((ele) => { ele() }) // 打印 10次 10 // after var funcs = []; for(let i = 0; i < 10; i++) { funcs.push(() => {console.log(i)}) } funcs.forEach((ele) => { ele() }) // 打印 0 1 2 3 4 5 6 7 8 9
注意:有一點很重要,let 聲明在循環內部的行爲是標準中專門定義的,它不必定與 let 不提高特性有關。
循環中的const聲明
// for 循環會報錯 for (const i = 0; i < 1; i++) { console.log(i) } // 打印 0 ,而後報錯 Assignment to constant variable. // for-in 和 for-of 不會報錯 var object = { a: true, b: true, c: true }; for (const key in object) { // 不要在循環體內更改key的值,會報錯 console.log(key) } // 打印 a b c
注意:const能夠應用在 for-in 和 for-of 循環中,是由於每次迭代不會修改已有綁定,而是會建立一個新綁定。
ES6 早期
廣泛認爲默認使用let來替代var,對於寫保護的變量使用const
ES6 使用中
廣泛默認使用const,只有確實須要改變變量的值時使用let。由於大部分變量的值在初始化後不該再改變,而預料以外的變量值的改變是許多bug的源頭。這樣就能夠在某種程度上實現代碼的不可變,從而防止某些錯誤的發生。
頂層對象,在瀏覽器環境指的是window對象,在Node指的是global對象。
爲了保持兼容性,var命令和function命令聲明的全局變量,依舊是頂層對象的屬性;
var a = 1; window.a // 1
另外一方面規定,let命令、const命令、class命令聲明的全局變量,不屬於頂層對象的屬性。
上圖可見let 聲明的變量,並無在Window對象裏,而是一個新的Script對象。
擴展:若是須要在瀏覽器中跨frame或window訪問代碼,仍然能夠用var在全局對象下定義變量。
從ECMAScript 6開始,在嚴格模式下,塊裏的函數做用域爲這個塊。ECMAScript 6以前不建議塊級函數在嚴格模式下使用。
'use strict'; function f() { return 1; } { function f() { return 2; } } f() === 1; // true // f() === 2 在非嚴格模式下相等
注意:在非嚴格模式下不要用塊級函數,由於在非嚴格模式下,塊中函數的聲明表現奇怪,有兼容性風險
if (shouldDefineZero) { function zero() { // DANGER: 兼容性風險 console.log("This is zero."); } }
ECMAScript 6中,若是shouldDefineZero是false,則永遠不會定義zero,由於這個塊不執行。這是新標準定義的。然而,這裏存在歷史遺留問題,不管這個塊是否執行,一些瀏覽器會定義zero。
在嚴格模式下,全部支持ECMAScript 6的瀏覽器以相同的方式處理:只有在shouldDefineZero爲true的狀況下定義zero,而且做用域只是這個塊內。