用於聲明變量。javascript
1) 所聲明的變量只在let命令所在代碼塊內有效。(塊級做用域)html
{ let a=10; var b=1; } a // ReferenceError: a is not defined
b // 1
var li=document.getElementsByTagName("li"); for(let i=0;i<li.length;i++){ li[i].addEventListener("click",function(){ console.log(i+1); }) }
在上面的代碼中,變量i是let聲明的,當前的i只在本輪循環有效,因此每一次循環的i都是一個新變量,因而最後輸出的是6。這樣每一個li元素輸出的都是不同的值,好比第一個li單擊會輸出1,第二個li單擊會輸出2,第三個li單擊會輸出3... java
2) 不存在變量提高瀏覽器
let不像var那樣會發生「變量提高」現象。因此變量必定要在聲明後使用,不然報錯。安全
console.log(foo); // ReferenceError
let foo=2; console.log(bar); // undefined
var bar=2;
因此typeof再也不是一個百分之百安全的操做了。ide
typeof x; // ReferenceError
let x;
3) 暫時性死區函數
只要塊級做用域內存在let命令,它所聲明的變量就「綁定」到這個區域,再也不受外部的影響。ES6明確規定,若是區塊中存在let和const命令,則這個區塊對這些命令聲明的變量從一開始就造成封閉做用域。只要在聲明以前就使用這些變量,就會報錯。在代碼塊內,使用let命令聲明變量以前,該變量都是不可用的。這在語法上稱爲「暫時性死區」(TDZ)。spa
if(true){ // TDZ開始
temp="abc"; // ReferenceError
console.log(temp); // ReferenceError
let temp; // TDZ結束
console.log(temp); // undefined
temp=123; console.log(temp); // 123
}
有些死區比較隱蔽,不太容易發現。code
function bar(x=y,y=2){ return [x,y]; } bar(); // 報錯
調用bar函數報錯,是由於參數x的默認值等於另外一個參數y,而此時y尚未聲明,屬於死區。htm
總之,暫時性死區的本質就是,只要已進入當前做用域,所要使用的變量就已存在,可是不可獲取,只有等到聲明變量的那一行代碼出現,才能夠獲取和使用該變量。
4) 不容許重複聲明
let不容許在相同的做用域內重複聲明同一個變量。
function func(){ // 報錯重複聲明變量
let a=10; var a=1; } function func(arg){ let arg; // 報錯,重複聲明變量
} function func(arg){ // 不報錯
{ let arg; } }
let實際上爲javascript新增了塊級做用域。
function f1(){ let n=5; if(true){ let n=10; } console.log(n); // 5
}
上面的函數有兩個代碼塊,都聲明瞭變量n,運行後輸出5.這表示外層代碼塊不受內層代碼塊的影響。
ES6容許塊級做用域任意嵌套。外層做用域沒法讀取內層做用域的變量。內層做用域能夠定義外層做用域的同名變量。
函數自己的做用域在其所在的塊級做用域內。
function f(){console.log('I am outside');} (function(){ if(false){ function f(){console.log('I am inside');} } f(); }());
上面的代碼在ES5中運行,會獲得I am inside(函數變量提高)。可是在ES6中運行會獲得I am outside。無論會不會進入if代碼塊,其內部聲明的函數皆不會影響到做用域的外部。
{ let a='secret'; function f(){ return a; } } f() // 報錯
塊級做用域外部沒法調用塊級做用域內部定義的函數。若是確實須要調用,則要像下面這樣處理
let f; { let a='secret'; f=function(){ return a; } } f() // secret
若是在嚴格模式下,函數只能在頂層做用域和函數內聲明,其餘狀況(好比if代碼塊,循環代碼塊)下的聲明都會報錯。
const用來聲明常量。一旦聲明,其值就不能改變。const一旦聲明常量,就必須當即初始化,不能留到之後賦值,只聲明不賦值就會報錯。
const PI=3.14; PI // 3.14
PI=3; // TypeError:"PI" is read-only
const做用域與let命令相同:只在聲明所在的塊級做用域內有效。const命令聲明的常量也不能提高,一樣存在暫時性死區,只能在聲明後使用。而且不能重複聲明常量。
對於複合類型的變量,變量名不指向數據,而是指向數據所在的地址。const命令只是保證變量名指向的地址不變,並不保證該地址的數據不變,因此將一個對象聲明爲常量必須很是當心。
const foo={}; foo.prop=123; foo={} // TypeError:"foo" is read-only
上面的代碼中,常量foo儲存的是一個地址,指向一個對象。不可變的只是這個地址,既不能把foo指向另外一個地址,但對象自己是可變的,因此依然能夠爲其添加新屬性。
const a=[]; a.push("Hello"); // 可執行 a.length=0; // 可執行 a=["Dave"]; // 報錯
若是真的想將對象凍結,應該使用Object.freeze方法。
const foo=Object.freeze({}); foo.prop=123; // 不起做用
上面的代碼中,常量foo指向一個凍結的對象,因此添加新屬性不起做用。除了將對象自己凍結,對象的屬性也應該凍結。下面是一個將對象完全凍結的函數。
var constantize=(obj)=>{ Object.freeze(obj); Object.keys(obj).forEach((key,value)=>{ if(typeof obj[key]==='object'){ constantize(obj[key]); } }) }
ES6有6種聲明變量的方法: var function let const import class
上面說過,const聲明的常量只在當前代碼塊有效。若是想設置跨模塊的常量,能夠採用下面的寫法:
// constants.js 模塊
export const A=1; export const B=3; export const C=4; // test1.js
import * as constants from './constants'; console.log(constants.A); // 1
console.log(constants.B); // 3
// test2.js
import {A,B} from './constants'; console.log(A); // 1
console.log(B); // 3
全局對象是最頂層的對象,在瀏覽器環境指的是window對象,在Node.js中指的是global對象。
ES6規定var 命令和function命令聲明的全局變量依舊是全局對象的屬性;let命令、const命令和class命令聲明的全局變量不屬於全局對象的屬性。
window.a=1; a; //1
a=2; window.a //2
let b=1; window.b // undefined