咱們知道es5中 var
聲明變量是做用於在全局或函數做用域,而且全局聲明的變量還會做爲 window
對象的屬性。這樣會增長程序錯誤的產生和不可控。es6
在全局或者函數做用內用 var
聲明的變量,在js預編譯階段會提高到當前做用域的頂部,這就是變量提高。以下代碼:函數
function getValue(condition) {
if (condition) {
var value = 'red';
} else {
console.log(value); // undefined
}
console.log(value); // undefined
}
複製代碼
以上代碼至關於把變量value放在當前做用域先聲明,因此才能在if塊外和else塊訪問到,都會輸出 undefined
。post
function getValue(condition) {
var value;
if (condition) {
value = 'red';
} else {
console.log(value); // undefined
}
console.log(value); // undefined
}
複製代碼
從上面的能夠看出 var
聲明的變量沒有塊級做用域的概念,因此es6引入了let
聲明,並綁定在當前的塊做用域,塊做用域外訪問報錯,以下:ui
function getValue(condition) {
if (condition) {
let value = 'red';
} else {
console.log(value); // ReferenceError: value is not defined
}
console.log(value); // ReferenceError: value is not defined
}
複製代碼
禁止重複聲明。在同一個塊中不能用 let
聲明已經存在的標識符,不然會報錯。若是是嵌套的做用域中重複聲明,則不會報錯。es5
var count = 30;
let count = 30; // SyntaxError: Identifier 'count' has already been declared
if (true) {
let count = 30; // 不會報錯
}
複製代碼
在es6引入const
來進行常量的聲明。他和前面的 let
同樣有塊做用域綁定和不準重複聲明的特性。可是const
必需要在聲明的階段進行初始化,而let
不用。spa
let count; // 不會報錯
const count; //SyntaxError: Missing initializer in const declaration
const count = 30; // 正確聲明
複製代碼
const
聲明的變量不能再賦值。若是變量是引用類型,能夠修改對象的屬性值,但不能夠從新修改綁定的對象。code
const count = 20;
count = 30; // TypeError: Assignment to constant variable.
const obj = {};
obj.name = 'wozien';
複製代碼
因爲let
與 const
不存在變量提高,因此在聲明前使用該變量會報錯。由於在聲明前,該變量存在於所謂的臨時死區(TDZ)。對象
if (true) {
console.log(typeof value);
let value = 'red'; // ReferenceError: value is not defined
}
複製代碼
當變量聲明後,就會從臨時死區移出,後續可正常訪問。注意的是,TDZ是針對當前的塊做用域而言,因此以下能夠正確運行:作用域
console.log(typeof value); // undefiend
if (true) {
let value = 'red';
}
複製代碼
在 var
聲明的循環變量,會在循環後外部可正常訪問,而且值爲跳出循環的值。let
聲明的變量則只在循環體內有效,以下:開發
for (var i = 0; i < 5; i++) {}
console.log(i); // 5
for (let i = 0; i < 5; i++) {}
console.log(i); // ReferenceError: i is not defined
複製代碼
在利用 var
聲明的循環中建立函數會變得很艱難,由於函數執行的時候是迭代完的最終,以下:
const func = [];
for (var i = 0; i < 3; i++) {
func.push(() => {
console.log(i);
});
}
func.forEach(func => func()); // 2 2 2
複製代碼
咱們能夠利用當即執行函數(IIFE)解決這個問題,讓每一個函數最終保存的是迭代過程當中變量的副本。
for (var i = 0; i < 3; i++) {
(function(value) {
func.push(() => console.log(value));
})(i);
}
複製代碼
在es6中循環裏面 let
聲明能夠用來簡化上面IIFE的實現過程,他會在每次迭代過程當中從新聲明一個同名變量i,值爲當前的迭代i的值,因此循環體內的函數使用的都是i值的副本。
for (let i = 0; i < 3; i++) {
func.push(() => console.log(i));
}
func.forEach(func => func()); // 0 1 2
複製代碼
若是把 let
改爲 const
, 在第二次迭代的時候會報錯,由於 const
不準從新賦值。而對於 for-in
和 for-of
循環二者均可以正常的運行。
const obj = {
a: 1,
b: 2,
c: 3
};
const func = [];
for (let key in obj) {
func.push(() => console.log(key));
}
func.forEach(func => func()); // a b c
複製代碼
若是把let
替換成 var
,將會輸出3個c。由於 for-in
和 for-of
每次都只會從新聲明一個新的副本key。
利用 var
在全局聲明變量,會做爲window對象的一個屬性存在,而 let
和 const
則不會。
var a = 1;
let b = 2;
const c = 3;
console.log(window.a); // 1
console.log(window.b); // undefined
console.log(window.c); // undefined
複製代碼
es6中的let
和 const
與 var
區別以下:
for
循環中每次建立新的副本window
屬性在咱們平時的開發中,能夠默認使用const
。在確認須要改變變量的值時才使用let
,能夠必定程序上防止代碼的錯誤產生。