1.let和const
1.let
let用于聲明變量,類似于var,但是所聲明的變量只在let命令所在的代碼塊內(nèi)有效。
for循環(huán)中的計數(shù)器非常適合使用let命令。
for(let i=0;i<10;i++){
.......
}
如果在外面打印i的haul,會報錯的,上面的代碼只在for循環(huán)內(nèi)有效,在循環(huán)體外就會報錯
var a=[];
for(var i=0;i<1o;i++){
a[i]=function(){
alert(i)
}
}
a[6]()=10;
變量i是var聲明的,在全局范圍內(nèi)都有效,所以全局只有一個變量i。每一次循環(huán),數(shù)組a的成員中的i指向的都是同一個i,導(dǎo)致運行時輸出的是最后一輪的i值,也就是10;
如果使用let,聲明變量僅僅在作用域內(nèi)有效,最后將輸出6
1..1.1.2不存在變量提升
var聲明可以有變量提升,即變量可以在聲明之前使用,打印的是undefined,let不存在這種變量提升,會直接報錯。
1.1.3
暫時性死區(qū)3
只要塊級作用域內(nèi)存在let命令,他所聲明的變量就綁定這個區(qū)域,不在受外部影響,代碼中存在全局變量,但是又在塊級作用域內(nèi)let聲明了一個局部變量,相同的變量名,導(dǎo)致后者綁定的這個塊級作用域,所以在let變量聲明前,會報錯
ES6明確規(guī)定,如果區(qū)塊中存在let和const命令,則這個區(qū)塊對這些命令聲明的變量一開始就形成封閉作用域,只要在變量之前使用這些變量,就會報錯。
總之,在代碼塊,使用let命令聲明變量之前,改變量都是不可用的,屬于“暫時性死區(qū)”。
暫時性死區(qū)的本質(zhì)就是只要進入當(dāng)前作用域,所要使用的變量就已經(jīng)存在,但是不可獲取,只有等到變量聲明的那一刻,才可以使用和獲取變量
1.1.4不允許重復(fù)聲明
let不允許在相同的作用域內(nèi)重復(fù)聲明同一個變量
2.2塊級作用域
2.1為什么需要塊級作用域
ES5只有全局作用于域和函數(shù)作用域
第一種場景:內(nèi)層變量可能會覆蓋外層變量。
var temp=new Date();
function f(){
alert(temp)
if(false){
var temp ="hello"
}
}
f()//undefined
以上代碼的愿意是,if代碼塊的外部使用外層的temp變量,內(nèi)部的使用內(nèi)部的temp變量,但是在函數(shù)f執(zhí)行的后,輸出的設(shè)計undefined,原因在于變量提升覆蓋了外層的temp變量。
第二種場景:用來技術(shù)的循環(huán)變量泄露為全局變量
var s="hello";
for (var i=0;i<s.length;i++){
alert(s[i])
}
console.log(i);
上面的代碼中,變量i只用來控制循環(huán),但是循環(huán)結(jié)束后,他沒有消失。而是泄露成了全局變量
2..2.2ES6的塊級作用域
let實際上為javaScript新增了塊級作用域
ES6允許塊級作用域的任意嵌套
{{{{{let a="kk}}}}}
上面一共有五層作用域,外層的作用域無法讀取內(nèi)層的作用域的變量
{{
{let k="ggg"}
console.log(k)會報錯,因為不在同一個作用域內(nèi)
}}
{{{
{let m="hello"}
{let m="hello"}
內(nèi)層作用域可以定義外層作用域的同名變量
}}}
2.2.3塊級作用域與函數(shù)聲明
Es5規(guī)定,函數(shù)只能在頂層作用域和函數(shù)作用域之中聲明,不能在塊級作用域聲明
ES6引入了塊級作用域,明確允許在塊級作用域之中聲明函數(shù)。ES6規(guī)定,在塊級作用域之中,函數(shù)聲明語句的行為類似于let,在塊級作用域之外不可引用。
ES6規(guī)定:
- 允許在會計作用與內(nèi)聲明函數(shù)
2.函數(shù)聲明類似于var,即會提升到全局作用域或者函數(shù)作用域的頂部
3.同時。函數(shù)聲明還會提升到所在的塊級作用域的頭部。
考慮到環(huán)境導(dǎo)致的行為差異太大,應(yīng)該避免在塊級作用域內(nèi)聲明函數(shù),如果確實需要,也應(yīng)該寫成函數(shù)表達式的形式,而不是函數(shù)聲明的形式,
函數(shù)表達式:let f=function(){
....
}
函數(shù)聲明:function f(){
....
}
另外:Es6的塊級作用域允許聲明函數(shù)的規(guī)則只在使用大括號的情況下成立,如果沒有使用大括號,就會報錯。必須將函數(shù)聲明放在大括號內(nèi)
if(true){
function f(){
....
}
}
應(yīng)該是這種寫法
2.2.4do表達式
本質(zhì)上,塊級作用域是一個語句,將多個封裝在一起,沒有返回值。
{
let t= f();
t=t*t+1;
}
上面,塊級作用域?qū)蓚€語句封裝在一起,但是,在塊級作用域之外,沒有辦法得到t的值,因為塊級作用域不返回值,除非t是全局變量。
現(xiàn)在使用do表達式,在塊級作用域上之前加上do
let x={
let t=f();
t*t+1;
}
上面的代碼中,變量x會得到整個塊級作用域的返回值
2.3const命令
2.3.1
const聲明了一個只讀的變量,一旦聲明,常量的值就不能更改。
對于const來說,只聲明不賦值就會報錯
const命令聲明的變量也不會提升,同樣存在暫時性死區(qū),只能在聲明后使用。
使用const聲明常量也與let一樣,不可重復(fù)聲明。
2.3.2
const實際上就是變量指向的那個內(nèi)存地址不得改動。對于簡單類型的數(shù)據(jù)(數(shù)值、字符串、布爾值),值就保存在變量指向的內(nèi)存地址中,因為等同于常量,對于復(fù)合類型的數(shù)據(jù)(對象和數(shù)組)來說,變量指向的內(nèi)存地址只是一個指針,const能保證這個指針是固定的,至于他的數(shù)據(jù)結(jié)構(gòu)是不是可變的。這是不能控制的,因此,將一個對象聲明為常量時必須小心。
2.3.3ES6聲明變量的6種方法
ES5只有兩種聲明變量的方法,使用Var和function;
ES6除了使用let和const,還會使用import和class命令,所以,es6一共有6個聲明變量的方法。
2.4頂層對象的屬性
頂層對象在瀏覽器環(huán)境中指的是window對象,在Node環(huán)境中指的是global對象,在es5中,頂層對象的屬性與全局變量是等價的。
es6規(guī)定var和function聲明的變量依舊是頂層對象的屬性,但是另一方面,let、const、calss、聲明的全局的變量不屬于頂層的屬性,也就是說,從es6開始,全局變量 將逐步與頂層對象的屬性隔離。
var a=1;
如果在Node的環(huán)境中,可寫成global.a
或者采用通用方法,this.a
window.a//1
let b=1;
window.b//undeifined;
上面,全局變量a由var命令聲明,所以他是頂層對象的屬性;全局變量b是由let聲明,所以他不是頂層對象的屬性,返回的是undefine
2.5global對象
在瀏覽器中,頂層對象是window,但在Node和web和web worker是沒有window
在node中,頂層對象是global,但其他的環(huán)境都不支持
。。。同一段代碼為了能夠在各種環(huán)境中都有取到的頂層對象,一般使用this變量,但是也有局限性。
1.在全局環(huán)境中,this會返回頂層對象,但是,在node模塊和Es6模塊中,this返回的是當(dāng)前模塊。
2.對于函數(shù)中this,如果函數(shù)不是作為對象對的方法運行,而是單純的作為函數(shù)運行,this會指向頂層對象,但是,在嚴格模式下,this會返回undefined。
3.不管是嚴格模式,還是普通模式,New Function(“return this”)() 總會返回全局對象。但是,如果瀏覽器用了CSP,那么eval 、New Function這些方法都無法使用。
綜上所述,很難找到一種方法可以在所有情況下都取到頂層對象。以下兩種勉強可以使用的方法。
方法一:
( typeof window !==="undefined"?window:(typeof self !=='undefined'))