let & const 命令

1、let命令

用於聲明變量。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; } }

 

 2、塊級做用域

 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代碼塊,循環代碼塊)下的聲明都會報錯

3、const命令

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

 

4、全局對象的屬性

全局對象是最頂層的對象,在瀏覽器環境指的是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
相關文章
相關標籤/搜索