JavaScript暫時性死區(qū)以及函數(shù)作用域
暫時性死區(qū)
暫時性死區(qū)也就是變量聲明到聲明完成的區(qū)塊,這個區(qū)塊是一個封閉的作用域,直到聲明完成。
如果在變量聲明之前使用該變量,那么該變量是不可用的,也就被稱為暫時性死區(qū)。
var沒有暫時性死區(qū),因為var存在變量提升let、const有塊級作用域,沒有變量提升,存在暫時性死區(qū)
console.log(a); // 報錯 Cannot access 'a' before initialization let a = '東方不敗'
console.log(b); // 報錯 Cannot access 'b' before initialization const b = '東方不敗'
console.log(c); // undefined 因為var存在變量提升 var c = '東方求敗'
ES6規(guī)定,如果代碼塊中存在let和const命令聲明的變量,這個區(qū)塊對這些變量從一開始就形成了封閉作用域,直到聲明語句完成,這些變量才能被訪問(獲取或設置),否則會報錯ReferenceError。這在語法上稱為“暫時性死區(qū)”(英temporal dead zone,簡 TDZ),既代碼塊開始到變量生命語句完成之前的區(qū)域。
函數(shù)作用域
案例一
一旦設置了參數(shù)的默認值,函數(shù)進行生命初始化時,參數(shù)就會形成一個單獨的作用域,等初始化結束,這個作用域就會消失,這種語法在不設置參數(shù)默認值時不會出現(xiàn)。
var x = 1
function f(x,y = x){
console.log(y);
}
f(2) // 2上面這個例子中,函數(shù)參數(shù)這里(x,y = x),這個區(qū)域就是單獨的作用域,y默認的x變量指向第一個參數(shù)x,而不是全局變量x,這里調用f函數(shù),向x傳遞數(shù)值2,y = x 那么 y = 2,打印結果為2
案例二
let x2 = 1
function f2(y2 = x2){
let x2 = 2
console.log(y2);
}
f2() // 1調用f2函數(shù),由于未給f2函數(shù)任何參數(shù),并且 y2 = x2 形成一個單獨的作用域,在這個作用域里x2并未定義,所以x2指向的是外層全局變量x2,y2 = x2 也就是y2 = 1,在這里,函數(shù)內部的x2并未起到任何作用。
函數(shù)執(zhí)行的時候會先執(zhí)行參數(shù),再執(zhí)行函數(shù)體。
// 報錯
function f2(y2 = x2){
let x2 = 2
console.log(y2);
}
f2() // 報錯上面的例子中,如果去掉全局變量x2則會報錯,因為變量未聲明,給y2賦值了一個未聲明的變量,報錯。
var xx = 1
function fxx(xx = xx){
console.log(xx);
}
fxx()上面這個寫法也會報錯,由于函數(shù)的參數(shù)存在單獨的作用域,在這個參數(shù)作用域內,執(zhí)行結果為 let xx = xx,給xx賦值一個未聲明的變量xx報錯。(暫時性死區(qū))
如果函數(shù)的默認參數(shù)是函數(shù),該函數(shù)的作用域也要遵循這個規(guī)則。
let foo = 'out'
function bar(func = () => foo){
let foo = 'come'
console.log(func());
}
bar() // out這個例子中,函數(shù)的參數(shù)是func默認值是一個匿名函數(shù),返回值為變量foo,由于函數(shù)參數(shù)這里形成一個單獨的作用域,在這個作用域里面并沒有定義變量foo,所以foo會指向外層全局變量foo。如果去掉全局變量foo='out'報錯,賦值了一個未聲明的變量。
應用可以利用這個特性寫一個參數(shù)默認值錯誤拋出,如果參數(shù)并未傳參則拋出一個錯誤。
function throwErr(){
throw new Error('參數(shù)不得省略')
}
function omits(mustfn = throwErr()){
return mustfn
}
omits(); // 未傳參拋出錯誤 : 參數(shù)不得省略調用omits函數(shù)未傳參數(shù),該函數(shù)就會默認調用throwErr()函數(shù)并拋出錯誤。
如果將參數(shù)默認值設置為 undefined 則表示該參數(shù)是可以省略的。
rest參數(shù)
arguments
arguments可以獲得函數(shù)的參數(shù)值以及函數(shù)信息(name、length)等
function au(arr){
console.log('arguments:',arguments);
}
au(2,1,4,3)
可以通過數(shù)組方法對函數(shù)參數(shù)進行操作,例如排序。
arguments對象不是數(shù)組,而是一個類似數(shù)組的對象,為了使用數(shù)組的方法,必須使用Array.from先將其轉為數(shù)組。
function au(arr){
// 通過數(shù)組方法對函數(shù)參數(shù)進行排序
return Array.from(arguments).sort();
}
console.log(au(2,1,4,3)) // [1,2,3,4]
rest參數(shù)ES6提供了rest參數(shù),語法:(...變量名),其實就是剩余運算符,通過rest參數(shù)就可以很容易的對函數(shù)參數(shù)進行操作,并且
rest的參數(shù)是一個真正的數(shù)組。
// resy參數(shù)(剩余運算符)
function residue(...val){
console.log(val); // [1,2,3]
}
residue(1,2,3)rest參數(shù)(剩余運算符)只能放到最后一位,否則報錯
// function residue2(...val,b){} // 剩余運算符不是最后一位,報錯
function residue3(c,...val){
console.log(c,val); // 1 [2,3,4,5]
}
residue3(1,2,3,4,5)上面arguments完成的參數(shù)排序,使用rest可以很輕松的做到,并且語義更強,更方便閱讀。
let au2 = (...val) => val.sort() console.log(au2(2,1,4,3)); // [1, 2, 3, 4]
嚴格模式
ES5開始,函數(shù)內部可以設定為嚴格模式: function s(){ 'use strict'// 嚴格模式 }
// es5嚴格模式
function s(){
'use strict' // 嚴格模式
// 代碼.....
}ES6做了修改,規(guī)定只要函數(shù)參數(shù)使用了默認值、解構賦值、擴展運算符,那么函數(shù)內部就不能顯示設定為嚴格模式,否則報錯。
// es6嚴格模式 報錯,因為設置了函數(shù)默認值
function s2(a,b = a){
'use strict'
// 代碼.....
}// 報錯,使用了解構賦值
const s3 = function({a,b}){
'use strict'
}// 報錯,使用了剩余運算符
const s4 = (...a) => {
'use strict'
}es6這樣設置的原因是,函數(shù)內部的嚴格模式應該同樣適用于函數(shù)體和函數(shù)參數(shù),但是,函數(shù)執(zhí)行的時候會先執(zhí)行參數(shù),再執(zhí)行函數(shù)體,這樣就有一些不嚴謹?shù)那闆r,只有函數(shù)體中才能知道參數(shù)是否應該以嚴格模式執(zhí)行,但是函數(shù)的參數(shù)確是先執(zhí)行,所以es6修改了函數(shù)參數(shù)關于嚴格模式的行為。
function s5(val = 070){
'use strict'
return val
}
s5() // 報錯這一段,函數(shù)的默認值是八進制070,嚴格模式下不能使用前綴0表示八進制,所以報錯。
但實際上是因為函數(shù)設置了默認參數(shù)的原因,函數(shù)先執(zhí)行參數(shù),再進函數(shù)體,由于es6限制,報錯。
有兩種方法可以規(guī)避這種限制
第一種:設置全局嚴格模式
'use strict'
function s6(val = 100){
console.log(val);
}
s6() // 100第二種方法:把函數(shù)嵌套在一個無參數(shù)的立即執(zhí)行函數(shù)里
const s7 = () => {
'use strict'
let a;
return (function(val = 200){ return val })()
}
console.log(s7());匿名函數(shù)的調用方法:在上述例子(function(val = 200){return val})()中,將整個return的函數(shù)用()套起來,尾部加一個()調用即可,()在函數(shù)中代表調用。
案例源碼:https://gitee.com/wang_fan_w/es6-science-institute
以上就是JavaScript暫時性死區(qū)以及函數(shù)作用域的詳細內容,更多關于JS暫時性死區(qū)函數(shù)作用域的資料請關注腳本之家其它相關文章!
相關文章
javascript實現(xiàn)的網站訪問量統(tǒng)計代碼
本文文章通過兩段代碼實例給大家介紹了基于javascript實現(xiàn)網站訪問量統(tǒng)計代碼,對js實現(xiàn)網站訪問量統(tǒng)計相關知識感興趣的朋友一起學習吧2015-12-12
詳解JavaScript中new操作符的解析和實現(xiàn)
這篇文章主要介紹了JavaScript中new操作符的解析和實現(xiàn),幫助大家更好的理解和學習JavaScript,感興趣的朋友可以了解下2020-09-09

