JavaScript暫時(shí)性死區(qū)以及函數(shù)作用域
暫時(shí)性死區(qū)
暫時(shí)性死區(qū)也就是變量聲明到聲明完成的區(qū)塊,這個(gè)區(qū)塊是一個(gè)封閉的作用域,直到聲明完成。
如果在變量聲明之前使用該變量,那么該變量是不可用的,也就被稱為暫時(shí)性死區(qū)。
var沒有暫時(shí)性死區(qū),因?yàn)?code>var存在變量提升let、const有塊級作用域,沒有變量提升,存在暫時(shí)性死區(qū)
console.log(a); // 報(bào)錯(cuò) Cannot access 'a' before initialization let a = '東方不敗'
console.log(b); // 報(bào)錯(cuò) Cannot access 'b' before initialization const b = '東方不敗'
console.log(c); // undefined 因?yàn)関ar存在變量提升 var c = '東方求敗'
ES6規(guī)定,如果代碼塊中存在let和const命令聲明的變量,這個(gè)區(qū)塊對這些變量從一開始就形成了封閉作用域,直到聲明語句完成,這些變量才能被訪問(獲取或設(shè)置),否則會(huì)報(bào)錯(cuò)ReferenceError。這在語法上稱為“暫時(shí)性死區(qū)”(英temporal dead zone,簡 TDZ),既代碼塊開始到變量生命語句完成之前的區(qū)域。
函數(shù)作用域
案例一
一旦設(shè)置了參數(shù)的默認(rèn)值,函數(shù)進(jìn)行生命初始化時(shí),參數(shù)就會(huì)形成一個(gè)單獨(dú)的作用域,等初始化結(jié)束,這個(gè)作用域就會(huì)消失,這種語法在不設(shè)置參數(shù)默認(rèn)值時(shí)不會(huì)出現(xiàn)。
var x = 1
function f(x,y = x){
console.log(y);
}
f(2) // 2上面這個(gè)例子中,函數(shù)參數(shù)這里(x,y = x),這個(gè)區(qū)域就是單獨(dú)的作用域,y默認(rèn)的x變量指向第一個(gè)參數(shù)x,而不是全局變量x,這里調(diào)用f函數(shù),向x傳遞數(shù)值2,y = x 那么 y = 2,打印結(jié)果為2
案例二
let x2 = 1
function f2(y2 = x2){
let x2 = 2
console.log(y2);
}
f2() // 1調(diào)用f2函數(shù),由于未給f2函數(shù)任何參數(shù),并且 y2 = x2 形成一個(gè)單獨(dú)的作用域,在這個(gè)作用域里x2并未定義,所以x2指向的是外層全局變量x2,y2 = x2 也就是y2 = 1,在這里,函數(shù)內(nèi)部的x2并未起到任何作用。
函數(shù)執(zhí)行的時(shí)候會(huì)先執(zhí)行參數(shù),再執(zhí)行函數(shù)體。
// 報(bào)錯(cuò)
function f2(y2 = x2){
let x2 = 2
console.log(y2);
}
f2() // 報(bào)錯(cuò)上面的例子中,如果去掉全局變量x2則會(huì)報(bào)錯(cuò),因?yàn)樽兞课绰暶?,給y2賦值了一個(gè)未聲明的變量,報(bào)錯(cuò)。
var xx = 1
function fxx(xx = xx){
console.log(xx);
}
fxx()上面這個(gè)寫法也會(huì)報(bào)錯(cuò),由于函數(shù)的參數(shù)存在單獨(dú)的作用域,在這個(gè)參數(shù)作用域內(nèi),執(zhí)行結(jié)果為 let xx = xx,給xx賦值一個(gè)未聲明的變量xx報(bào)錯(cuò)。(暫時(shí)性死區(qū))
如果函數(shù)的默認(rèn)參數(shù)是函數(shù),該函數(shù)的作用域也要遵循這個(gè)規(guī)則。
let foo = 'out'
function bar(func = () => foo){
let foo = 'come'
console.log(func());
}
bar() // out這個(gè)例子中,函數(shù)的參數(shù)是func默認(rèn)值是一個(gè)匿名函數(shù),返回值為變量foo,由于函數(shù)參數(shù)這里形成一個(gè)單獨(dú)的作用域,在這個(gè)作用域里面并沒有定義變量foo,所以foo會(huì)指向外層全局變量foo。如果去掉全局變量foo='out'報(bào)錯(cuò),賦值了一個(gè)未聲明的變量。
應(yīng)用可以利用這個(gè)特性寫一個(gè)參數(shù)默認(rèn)值錯(cuò)誤拋出,如果參數(shù)并未傳參則拋出一個(gè)錯(cuò)誤。
function throwErr(){
throw new Error('參數(shù)不得省略')
}
function omits(mustfn = throwErr()){
return mustfn
}
omits(); // 未傳參拋出錯(cuò)誤 : 參數(shù)不得省略調(diào)用omits函數(shù)未傳參數(shù),該函數(shù)就會(huì)默認(rèn)調(diào)用throwErr()函數(shù)并拋出錯(cuò)誤。
如果將參數(shù)默認(rèn)值設(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ù)進(jìn)行操作,例如排序。
arguments對象不是數(shù)組,而是一個(gè)類似數(shù)組的對象,為了使用數(shù)組的方法,必須使用Array.from先將其轉(zhuǎn)為數(shù)組。
function au(arr){
// 通過數(shù)組方法對函數(shù)參數(shù)進(jìn)行排序
return Array.from(arguments).sort();
}
console.log(au(2,1,4,3)) // [1,2,3,4]
rest參數(shù)ES6提供了rest參數(shù),語法:(...變量名),其實(shí)就是剩余運(yùn)算符,通過rest參數(shù)就可以很容易的對函數(shù)參數(shù)進(jìn)行操作,并且
rest的參數(shù)是一個(gè)真正的數(shù)組。
// resy參數(shù)(剩余運(yùn)算符)
function residue(...val){
console.log(val); // [1,2,3]
}
residue(1,2,3)rest參數(shù)(剩余運(yùn)算符)只能放到最后一位,否則報(bào)錯(cuò)
// function residue2(...val,b){} // 剩余運(yùn)算符不是最后一位,報(bào)錯(cuò)
function residue3(c,...val){
console.log(c,val); // 1 [2,3,4,5]
}
residue3(1,2,3,4,5)上面arguments完成的參數(shù)排序,使用rest可以很輕松的做到,并且語義更強(qiáng),更方便閱讀。
let au2 = (...val) => val.sort() console.log(au2(2,1,4,3)); // [1, 2, 3, 4]
嚴(yán)格模式
ES5開始,函數(shù)內(nèi)部可以設(shè)定為嚴(yán)格模式: function s(){ 'use strict'// 嚴(yán)格模式 }
// es5嚴(yán)格模式
function s(){
'use strict' // 嚴(yán)格模式
// 代碼.....
}ES6做了修改,規(guī)定只要函數(shù)參數(shù)使用了默認(rèn)值、解構(gòu)賦值、擴(kuò)展運(yùn)算符,那么函數(shù)內(nèi)部就不能顯示設(shè)定為嚴(yán)格模式,否則報(bào)錯(cuò)。
// es6嚴(yán)格模式 報(bào)錯(cuò),因?yàn)樵O(shè)置了函數(shù)默認(rèn)值
function s2(a,b = a){
'use strict'
// 代碼.....
}// 報(bào)錯(cuò),使用了解構(gòu)賦值
const s3 = function({a,b}){
'use strict'
}// 報(bào)錯(cuò),使用了剩余運(yùn)算符
const s4 = (...a) => {
'use strict'
}es6這樣設(shè)置的原因是,函數(shù)內(nèi)部的嚴(yán)格模式應(yīng)該同樣適用于函數(shù)體和函數(shù)參數(shù),但是,函數(shù)執(zhí)行的時(shí)候會(huì)先執(zhí)行參數(shù),再執(zhí)行函數(shù)體,這樣就有一些不嚴(yán)謹(jǐn)?shù)那闆r,只有函數(shù)體中才能知道參數(shù)是否應(yīng)該以嚴(yán)格模式執(zhí)行,但是函數(shù)的參數(shù)確是先執(zhí)行,所以es6修改了函數(shù)參數(shù)關(guān)于嚴(yán)格模式的行為。
function s5(val = 070){
'use strict'
return val
}
s5() // 報(bào)錯(cuò)這一段,函數(shù)的默認(rèn)值是八進(jìn)制070,嚴(yán)格模式下不能使用前綴0表示八進(jìn)制,所以報(bào)錯(cuò)。
但實(shí)際上是因?yàn)楹瘮?shù)設(shè)置了默認(rèn)參數(shù)的原因,函數(shù)先執(zhí)行參數(shù),再進(jìn)函數(shù)體,由于es6限制,報(bào)錯(cuò)。
有兩種方法可以規(guī)避這種限制
第一種:設(shè)置全局嚴(yán)格模式
'use strict'
function s6(val = 100){
console.log(val);
}
s6() // 100第二種方法:把函數(shù)嵌套在一個(gè)無參數(shù)的立即執(zhí)行函數(shù)里
const s7 = () => {
'use strict'
let a;
return (function(val = 200){ return val })()
}
console.log(s7());匿名函數(shù)的調(diào)用方法:在上述例子(function(val = 200){return val})()中,將整個(gè)return的函數(shù)用()套起來,尾部加一個(gè)()調(diào)用即可,()在函數(shù)中代表調(diào)用。
案例源碼:https://gitee.com/wang_fan_w/es6-science-institute
以上就是JavaScript暫時(shí)性死區(qū)以及函數(shù)作用域的詳細(xì)內(nèi)容,更多關(guān)于JS暫時(shí)性死區(qū)函數(shù)作用域的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JS自動(dòng)生成動(dòng)態(tài)HTML驗(yàn)證碼頁面
這篇文章主要介紹了JS自動(dòng)生成動(dòng)態(tài)HTML驗(yàn)證碼頁面,輸入錯(cuò)誤自動(dòng)清空輸入框的功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
如何讓每個(gè)Http請求都自動(dòng)帶上token
這篇文章主要介紹了如何讓每個(gè)Http請求都自動(dòng)帶上token問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
JS實(shí)現(xiàn)移動(dòng)端判斷上拉和下滑功能
通過手指觸屏,利用touchstart和touchend計(jì)算前后滑動(dòng)距離,判斷是上拉還是下滑。接下來通過實(shí)例代碼給大家介紹js移動(dòng)端判斷上拉和下滑功能,感興趣的朋友一起看看吧2017-08-08
javascript實(shí)現(xiàn)的網(wǎng)站訪問量統(tǒng)計(jì)代碼
本文文章通過兩段代碼實(shí)例給大家介紹了基于javascript實(shí)現(xiàn)網(wǎng)站訪問量統(tǒng)計(jì)代碼,對js實(shí)現(xiàn)網(wǎng)站訪問量統(tǒng)計(jì)相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2015-12-12
小程序?qū)崿F(xiàn)自定義導(dǎo)航欄適配完美版
這篇文章主要介紹了小程序?qū)崿F(xiàn)自定義導(dǎo)航欄適配完美版,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
詳解JavaScript中new操作符的解析和實(shí)現(xiàn)
這篇文章主要介紹了JavaScript中new操作符的解析和實(shí)現(xiàn),幫助大家更好的理解和學(xué)習(xí)JavaScript,感興趣的朋友可以了解下2020-09-09

