1. var變量聲明提升
var聲明的變量侄柔,發(fā)生變量聲明提升;即:變量的聲明被提升到該作用域的頂部
let 和 const 聲明的變量不會發(fā)生變量提升,產(chǎn)生暫時死區(qū)(TDZ)占调,訪問a的時候變量沒有聲明暂题,會報錯; 注:由于出現(xiàn)let聲明,所以出現(xiàn)TDZ
var a=10;
function fn(){
console.log(a)
var a=90
}
fn()
// 相當(dāng)于以下代碼:
var a=10; // 全局變量a
function fn(){
var a // 局部變量a究珊,變量a的聲明提升到此處了
console.log(a) // 變量a只是聲明了薪者,沒有定義,所以是undefined
a=90 // 變量a被定義
}
fn() // 打印undefined剿涮,變量聲明提升言津,代碼按順序執(zhí)行
2. 預(yù)處理
在局部作用域中攻人,如果有局部變量,則不會訪問同名的全局變量悬槽,否則怀吻,訪問全局變量
var的變量聲明提升也是由于存在著預(yù)處理
var a=10;
function fn(){
// TDZ 開始
console.log(a)
// TDZ結(jié)束,'a'僅在此處初始化初婆,值為20
let a=20
}
fn() // 報錯 Uncaught ReferenceError: Cannot access 'a' before initialization
3. 作用域
let和const聲明的變量會產(chǎn)生塊級作用域
var聲明的變量會穿透if和for語句蓬坡,不會產(chǎn)生塊級作用域
var array=[]
for(var i=0;i<3;i++){
array.push(()=>i)
}
console.log(array) // [f,f,f],其中每個f都是()=>i
var newArray=array.map(el=>el()) //使用map循環(huán)執(zhí)行array中的每個元素(即f函數(shù))此時循環(huán)已經(jīng)結(jié)束,i為3
console.log(newArray) // [3,3,3]
解釋:誤解作用域磅叛,認(rèn)為for循環(huán)產(chǎn)生了塊級作用域; 在for循環(huán)中使用var聲明的變量屑咳,是單個聲明的變量綁定 (單個存儲空間),循環(huán)過程中弊琴,這個var聲明的變量i是會隨著循環(huán)變化的兆龙,但是,在循環(huán)中執(zhí)行的數(shù)組push方法敲董,最后實際上都push了i最終循環(huán)結(jié)束的3這個值紫皇,最后結(jié)果為[3,3,3]
解決以上問題就是需要創(chuàng)建真正的塊級作用域
方案1 :使用let聲明循環(huán)變量,這個為每個循環(huán)迭代創(chuàng)建一個新的綁定
var array=[]
for(let i=0;i<3;i++>){
array.push(()=>i)
}
var newArray=array.map(el=>el())
console.log(newArray) // [0,1,2]
方案2:使用閉包腋寨,形成塊級作用域
var array=[]
for(var i=0;i<3;i++){
array[i]=(function(x){
return function(){
return x
}
})(i)
}
var newArray=array.map(el=>el())
console.log(newArray) // [0,1,2]
4.作用域鏈
如果當(dāng)前作用域找不到變量聲明坝橡,則沿著作用域鏈向上查找,直到找到該變量精置,否則undefined
var a=10;
function fn(){
console.log(a)
}
fn() //最后打印的結(jié)果是:10