久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

javascipt作用域深入理解

 昵稱46000165 2017-08-02
                                                      
我們知道,,JavaScript中with語句和catch語句會延長作用域鏈,,例如下面這樣:
with({x:20}){
console.log(x);  //20
}
console.log(x)//拋出錯誤
很明顯,結(jié)果是控制臺打印出20,,然后拋出錯誤,,因為在with語句中作用域鏈被延長了(稱為壓棧),添加了一個新的作用域,,它就是with語句圓括號中的對象,。退出with語句后,作用域鏈會被縮短到原來的長度(稱為出棧),。那么,,要是這樣呢:
with({x:20}){
var x=30;
}
console.log(x);//問題1
很多人猜結(jié)果是拋出錯誤,但其實是undefined。為什么,?下面先引出幾個概念:
1.執(zhí)行上下文
2.作用域鏈(scope)
3.變量對象
4.活躍對象 
執(zhí)行上下文:執(zhí)行上下文是可執(zhí)行代碼的環(huán)境,,每一個函數(shù)調(diào)用都會進入一個新的執(zhí)行上下文,執(zhí)行上下文可想象成一個對象,,它擁有兩個重要的屬性,,一個是作用域鏈(scope),另一個是this(關(guān)鍵字this)。當函數(shù)拋出未捕獲錯誤的時候,,錯誤會沿著執(zhí)行上下文拋出,,每拋出一個執(zhí)行上下文,執(zhí)行上下文鏈頂端的對象會被彈出棧,,直到錯誤被捕獲或者程序退出 運行,。

作用域鏈:首先解釋什么是作用域,Javascript 中的作用域本質(zhì)上是一個對象,,它保存著執(zhí)行上下文上聲明的變量,。當引用一個變量的時候,就是在作用域上查找這個變量的值,。顧名思義,,作用域鏈就是一系列有先后順序串聯(lián)在一起的作用域。全局執(zhí)行上下文中的作用域鏈只有一個作用域,,在瀏覽器端那就是我們熟知的window,。當查找 一個變量的時候,會先查找作用域鏈最前面的元素,,如果找不到,會遞歸查找次前面的元素,,直到找到,。當作用域鏈中的元素被遍歷完后如果還是找不到對應(yīng)的變量,會拋出錯誤,。

變量對象:變量對象用于保存在執(zhí)行上下文中聲明的變量,,執(zhí)行上下文中聲明的變量的名字會作為變量對象的屬性,聲明的值會作為變量對象中相應(yīng)屬性的值,。在全局執(zhí)行上下文中,,變量對象就是全局對象,執(zhí)行上下文中的this對象也是全局對象(在瀏覽器端時window)

活躍對象:當調(diào)用一個函數(shù)的時候,,執(zhí)行會被分為兩個階段,。
第一階段是進入執(zhí)行上下文階段,這個時候會發(fā)生幾件事:
1.創(chuàng)建一個新的執(zhí)行上下文,,并把它拼在執(zhí)行上下文鏈的最前端
2.創(chuàng)建一個活躍對象,,這個活躍對象有一個屬性,它就是arguments,,值就是傳入函數(shù)的實參值組成的類數(shù)組,。
3.為當前執(zhí)行上下文分配一個作用域鏈(scope)
4.創(chuàng)建變量對象,,此時并沒有真正創(chuàng)建一個新變量對象,而是把第二步中創(chuàng)建的活躍對象當做了變量對象
5.當前執(zhí)行上下文中的變量聲明初始化,,變量名作為變量對象的屬性名 ,,初始值為undefined,但有一個例外,,那就是函數(shù)聲明是的形參名也會作為變量對象的屬性名,,且值初始化為傳進來的實參值,對于沒有傳進來的形參,,值為undefined,。還有一個例外就是函數(shù)聲明,其初始值設(shè)為聲明的函數(shù)對象,。
6.為關(guān)鍵字this分配一個值

第二階段是執(zhí)行代碼階段,,這一階段可能會重置變量的初始值

當聲明一個函數(shù)時,會為這個函數(shù)分配一個內(nèi)部屬性[[scope]](不同于上面的scope),,每一個執(zhí)行上下文都會有一個對于的scope(作用域鏈),,函數(shù)內(nèi)部的[[scope]]引用的就是函數(shù)聲明所在執(zhí)行上下文所對應(yīng)的scope。當調(diào)用一個函數(shù)時,,會新建一個執(zhí)行上下文,,并且為它分配一個scope,這個新分配的scope有兩部分組成,,一個是函數(shù)內(nèi)部屬性[[scope]]所引用的作用域鏈,,加上一個函數(shù)執(zhí)行時所產(chǎn)生的活躍對象,活躍對象被拼接在新生產(chǎn)的scope鏈的最前面?,F(xiàn)在,,上面的'問題1'就解釋的通了:
with({x:20}){
var x=30;
}
console.log(x);//undefined
在with語句中,作用域鏈被延伸,,在原來作用域鏈的基礎(chǔ)上新增一個對象,,就是with語句圓括號中的那個。我們前面說過,,在進入執(zhí)行上下文的時候,,會有一個變量聲明初始化,而當進入執(zhí)行上下文的時候,,作用域鏈還沒被延伸呢(注意了即使進入with語句中還一樣是原來的執(zhí)行上下文,,執(zhí)行上下文的改變只在調(diào)用一個函數(shù)的時候),當前執(zhí)行上下文的作用域鏈的最強面是變量對象,,with語句中的var x=30,;聲明會在變量對象上新增一個屬性'x’,值為undefined。在執(zhí)行階段,進入with語句的時候,,作用域鏈被延伸,,對x的賦值其實是對{x:20}中的x賦值而不是變量對象中的x進行賦值,所以結(jié)果就是undefined,。

閉包:退出函數(shù)后,,執(zhí)行上下文會被銷毀,其對于的scope和this也不復(fù)存在,。那么,,為什么子函數(shù)還可以引用父函數(shù)中的變量呢?相信很多人多會有這個疑問,,現(xiàn)在來揭秘,。前面說過,聲明一個函數(shù)的時候,,它有一個內(nèi)部屬性[[scope]],,指向當前執(zhí)行上下文中的scope鏈。而scope鏈中的元素其實是對象,。當父元素執(zhí)行上下文銷毀后,,其scope鏈中的對象并不一定會被銷毀,因為JavaScript中的垃圾回收機制采用的是引用計數(shù)算法,,當聲明子函數(shù)的時候,,子函數(shù)內(nèi)部的[[scope]]屬性其實已經(jīng)引用了父函數(shù)執(zhí)行上下文中的scope,而父函數(shù)執(zhí)行上下文中的scope包含著父函數(shù)的變量對象,,所以當父函數(shù)對應(yīng)的scope銷毀后,,父函數(shù)的變量對象還會被子函數(shù)引用著(在子函數(shù)的[[scope]]中),即使子函數(shù)還沒有被調(diào)用,。這也解釋了為什么但一個父函數(shù)調(diào)用多次,,會產(chǎn)生多個互不相同的子函數(shù),并且不同的子函數(shù)不共用父函數(shù)中的變量,。
function parent(){
var x=1;
function child(){
x++;
console.log(x)
}
return child;
}
var child1=parent();
var child2=parent();
child1();//2 
child1();//3
child2();//2















    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多