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)文章
JavaScript基礎(chǔ)之靜態(tài)方法和實(shí)例方法分析
這篇文章主要介紹了JavaScript基礎(chǔ)之靜態(tài)方法和實(shí)例方法,簡單分析了javascript靜態(tài)方法及實(shí)例方法的定義、使用相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2018-12-12Javascript日期格式化format函數(shù)的使用方法
這篇文章主要介紹的是javascript時(shí)間格式format函數(shù),我們有時(shí)候調(diào)用的new Date()不是格式化的時(shí)間,可能顯示不是很正常,那么這時(shí)候就需要格式化時(shí)間,今天這里分享一個(gè)javascript的foramt()函數(shù),有需要的可以參考借鑒。2016-08-08json實(shí)現(xiàn)添加、遍歷與刪除屬性的方法
這篇文章主要介紹了json實(shí)現(xiàn)添加、遍歷與刪除屬性的方法,結(jié)合簡單實(shí)例形式分析了json常見的添加、遍歷與刪除操作相關(guān)技巧,需要的朋友可以參考下2016-06-06