let
和const
命令是ES6
新增的命令,用來聲明變量,這兩個變量跟ES5
中的var
有許多不一樣,同時let
和const
也有不同的地方。而且在ES6
中也添加了塊級做用域來解決ES5中做用域存在的問題。node
官方解釋是:「一段程序代碼中所用到的名字並不老是有效/可用的,而限定這個名字的可用性的代碼範圍就是這個名字的做用域。」 es6
舉個例子來形象的解析下上面的定義:數組
function fn () {
// 聲明變量
var name = 'marry'
// 定義內部函數
function innerFn () {
console.log(name) // 能夠訪問到name變量
}
}
console.log(name) // undefined
複製代碼
ES5做用域分爲全局做用域和函數做用域。瀏覽器
var a = 0;
if (true) {
var b = 1;
}
console.log(b); // 輸出1
複製代碼
上面代碼中,在全局中定義變量a,稱爲全局變量,在任何一個地方均可以訪問到變量a。安全
局部做用域也能夠稱之爲函數做用域。bash
function fn () {
var c = 2;
}
console.log(c); // c is not defined
複製代碼
Function對象有一個僅供 JavaScript
引擎存取的內部屬性。函數
這個屬性就是[[Scope]]
。[[Scope]]
包含了一個函數被建立的做用域中對象的集合。這個集合被稱爲函數的做用域鏈,它決定了哪些數據能被函數訪問。 關於做用域鏈,局部做用域能夠訪問到全局做用域中的變量和方法,而全局做用域不能訪問局部做用域的變量和方法。post
var a = 0;
function fn () {
var b = 1;
console.log(a); // 輸出 1
}
// 全局做用域並不能訪問 fn 函數中定義的 b 變量
console.log(b); // b is not defined
fn();
複製代碼
ES6
新增塊級做用域,塊做用域由 { }
包括,函數內部,if
語句和 for
語句裏面的{ }
也屬於塊做用域。ui
塊級做用域的出現是爲了解決ES5
中做用域的問題:this
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]); // i應該爲這次for循環使用的變量
}
console.log(i); // 5 全局範圍均可以讀到
複製代碼
塊級做用域
經過var
聲明的變量存在變量提高的特性
// var 的狀況
console.log(foo); // 輸出undefined
{ var foo = 2; }
console.log(foo) // 2
// 運行時,真正運行的是下面的代碼
var = foo
console.log(foo); // 輸出undefined
{ foo = 2; }
console.log(foo) // 2
複製代碼
除此以外,在for循環中:
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
複製代碼
上面代碼中,變量i是var命令聲明的,在全局範圍內都有效,因此全局只有一個變量i。
ES6 新增了let命令,用來聲明變量。它的用法相似於var,可是所聲明的變量,只在let命令所在的代碼塊內有效。
{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1
複製代碼
let命令所聲明的變量必定要在聲明後使用,不然報錯。
// var 的狀況
console.log(foo); // 輸出undefined
var foo = 2;
// let 的狀況
console.log(bar); // 報錯ReferenceError
let bar = 2;
複製代碼
let value = 2;
let value = 2; //Uncaught SyntaxError: Identifier 'value' has already been declared
複製代碼
瀏覽器環境頂層對象是: window; node環境頂層對象是: global
var a = 1;
// 若是在 Node環境,能夠寫成 global.a
// 或者採用通用方法,寫成 this.a
window.a // 1
let b = 1;
window.b // undefined
複製代碼
let p; var p1; // 不報錯
const p3 = 'abc'
const p3; // 報錯 沒有賦值
複製代碼
const p = '不能改變';
p = '報錯' // Assignment to constant variable
複製代碼
const foo = {};
// 爲 foo 添加一個屬性,能夠成功
foo.prop = 123;
foo.prop // 123
// 將 foo 指向另外一個對象,就會報錯
foo = {}; // TypeError: "foo" is read-only
複製代碼
const所說的一旦聲明值就不能改變,實際上指的是:變量指向的那個內存地址所保存的數據不得改動
只要一進入當前做用域,所要使用的變量就已經存在了,可是不可獲取,只有等到聲明變量的那一行代碼出現,才能夠獲取和使用該變量。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
複製代碼
總之,在代碼塊內,使用let
命令聲明變量以前,該變量都是不可用的。這在語法上,稱爲「暫時性死區」(temporal dead zone,簡稱 TDZ)。
暫時性死區和不能變量提高的意義在於:
爲了減小運行時錯誤,防止在變量聲明前就使用這個變量,從而致使意料以外的行爲。
var 和 let、const的區別
const須要注意點