let 是一個用來聲明變量的命令。它的用法相似於var ,可是所聲明的變量,只在let 命令所在的代碼塊內有效。javascript
JavaScript引擎中,代碼會在執行上下文中執行。而在執行上下文的建立階段,聲明的各類類型變量 (var
, let
, const
, function
, function*
, class
) 都會被添加到詞法環境中。html
let
, const
, class
的「建立」過程被提高了,可是「初始化」沒有提高。var
的「建立」過程被提高了,而且會被「初始化」爲undefined。function
, function*
的「建立」「初始化」和「賦值」都被提高了。function
, function*
提高的優先級別更高,更早被添加到詞法環境中。let
, const
, class
, function
, function*
被添加到詞法環境中,而 var
被添加到變量環境中。var
變量綁定。使用for循環時,發現let居然能夠重複定義同名變量:java
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
複製代碼
總結:這代表函數內部的變量i 與for循環變量i 不在同一個做用域。循環變量的那部分是一個父做用域,而循環體內部是一個單獨的子做用域。web
ES5 只有全局做用域和函數做用域,沒有塊級做用域,這帶來不少不合理的場景。編程
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
複製代碼
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
複製代碼
上面代碼中,變量i
只用來控制循環,可是循環結束後,它並無消失,泄露成了全局變量。數組
ES6 容許塊級做用域的任意嵌套瀏覽器
ES6 的塊級做用域必須有大括號markdown
內層做用域能夠定義外層做用域的同名變量數據結構
{{{{
let insane = 'Hello World';
{let insane = 'Hello World'}
}}}};
複製代碼
匿名當即執行函數表達式部分功能被替代模塊化
// IIFE 寫法
(function () {
var tmp = ...;
...
}());
// 塊級做用域寫法
{
let tmp = ...;
...
}
複製代碼
容許在塊級做用域之中聲明函數
ES6 規定,塊級做用域之中,函數聲明語句的行爲相似於let
,在塊級做用域以外不可引用。
var
)。const
聲明一個只讀的常量。一旦聲明,常量的值就不能改變。
只在聲明所在的塊級做用域內有效(與let
命令相同)。
const
命令聲明的常量也是無初始化提高,一樣存在暫時性死區。
const
聲明的常量,也與let
同樣不可重複聲明。
const
僅僅保證指向的內存地址數據不得改動。
對於簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,所以等同於常量。但對於複合類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個指向實際數據的指針,const
只能保證這個指針是固定的(即老是指向另外一個固定的地址),至於它指向的數據結構則是可變的。
若是想凍結對象,應該使用Object.freeze
方法。
var
命令和function
命令是ES5 中僅有的兩種聲明變量的方法。let
和const
命令,import
命令和class
命令則是ES6新增的聲明變量的方法。
window
對象,在 Node 指的是global
對象。var
命令和function
命令聲明的全局變量,依舊是頂層對象的屬性。let
命令、const
命令、class
命令聲明的全局變量,不屬於頂層對象的屬性。JavaScript 語言存在一個頂層對象,它提供全局環境(即全局做用域),全部代碼都是在這個環境中運行。可是,頂層對象在各類實現裏面是不統一的。
瀏覽器裏面,頂層對象是window
,但 Node 和 Web Worker 沒有window
。
瀏覽器和 Web Worker 裏面,self
也指向頂層對象,可是 Node 沒有self
。
Node 裏面,頂層對象是global
,但其餘環境都不支持。