最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解JavaScript中的作用域鏈與閉包

 更新時(shí)間:2022年11月30日 10:18:51   作者:大眼睛圖圖  
這篇文章主要為大家詳細(xì)介紹一下JavaScript中的作用域鏈與閉包的使用,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)JavaScript有一定的幫助,需要的可以參考一下

作用域鏈

首先來(lái)看看這段代碼:

var a = '喜羊羊';
function A(){
    console.log(a);
    a = '美羊羊';
    function B(){
        console.log(a);
    }
    B();
}
A();

在這里毫無(wú)疑問(wèn)結(jié)果肯定是我們想到的先打印喜羊羊,再打印美羊羊。因?yàn)樽饔糜蜴溌铮绻?dāng)前層沒(méi)找到,那么就去當(dāng)前層的上一級(jí)找。

那么再看這道

function bar() {
    console.log(myName)
}
function foo() {
    var myName = "極客邦"
    bar()
}
var myName = "極客時(shí)間"
foo()

是不是感覺(jué)是打印極客邦?如果是的話,那么恭喜你,掉坑里了。(還不趕快爬起來(lái),補(bǔ)一補(bǔ)作用域鏈的知識(shí))。

為什么打印不是極客邦而是極客時(shí)間呢?

既然問(wèn)題出現(xiàn)在了對(duì)作用域鏈的理解上,那么就再回到作用域鏈的定義上吧。

其實(shí)在每個(gè)執(zhí)行上下文的變量環(huán)境中,都包含了一個(gè)外部引用,用來(lái)指向外部的執(zhí)行上下文,我們把這個(gè)外部引用稱為 outer。

比如上面那段代碼在查找 myName 變量時(shí),如果在當(dāng)前的變量環(huán)境中沒(méi)有查找到,那么 JavaScript 引擎會(huì)繼續(xù)在 outer 所指向的執(zhí)行上下文中查找

為了直觀理解,你可以看下面這張圖:

看到這張圖我猜你又納悶了,為什么bar函數(shù)創(chuàng)建的執(zhí)行上下文中的outer會(huì)指向全局??

哈哈哈,這里就要涉及到了詞法作用域了

詞法作用域

詞法作用域就是指作用域是由代碼中函數(shù)聲明的位置來(lái)決定的,所以詞法作用域是靜態(tài)的作用域,通過(guò)它就能夠預(yù)測(cè)代碼在執(zhí)行過(guò)程中如何查找標(biāo)識(shí)符。

這么講可能不太好理解,你可以看下面這張圖:

從圖中可以看出,詞法作用域就是根據(jù)代碼的位置來(lái)決定的,其中 main 函數(shù)包含了 bar 函數(shù),bar 函數(shù)中包含了 foo 函數(shù),因?yàn)?JavaScript 作用域鏈?zhǔn)怯稍~法作用域決定的,所以整個(gè)詞法作用域鏈的順序是:foo 函數(shù)作用域—>bar 函數(shù)作用域—>main 函數(shù)作用域—> 全局作用域。

明白了詞法作用域,那么我們?cè)倩氐絼倓偟膯?wèn)題。

為什么bar函數(shù)創(chuàng)建的執(zhí)行上下文中的outer會(huì)指向全局

這是因?yàn)楦鶕?jù)詞法作用域,而詞法作用域又是根據(jù)代碼的位置,而bar函數(shù)代碼的位置就是包裹在全局下,而喜羊羊那個(gè)例子中的B函數(shù)是在A函數(shù)的環(huán)境下,所以會(huì)造成它們的詞法作用域鏈不同,也就導(dǎo)致函數(shù)作用域鏈不同了。

所以我們才有那句話詞法作用域是代碼編譯階段就決定好的,和函數(shù)是怎么調(diào)用的沒(méi)有關(guān)系。

也就是只和代碼位置有關(guān),和函數(shù)直接如何調(diào)用沒(méi)關(guān)系

閉包

老生常談的問(wèn)題,這次再?gòu)囊粋€(gè)更深入的角度來(lái)理解一下。

看下面這段代碼:

function foo() {
    var myName = "極客時(shí)間"
    let test1 = 1
    const test2 = 2
    var innerBar = {
        getName:function(){
            console.log(test1)
            return myName
        },
        setName:function(newName){
            myName = newName
        }
    }
    return innerBar
}
var bar = foo()
bar.setName("極客邦")
bar.getName()
console.log(bar.getName())

這段代碼乍一看沒(méi)有什么問(wèn)題,但是這里有一個(gè)細(xì)節(jié)很多人會(huì)忽視。

在foo()執(zhí)行完將返回值給bar時(shí),這里foo函數(shù)會(huì)從調(diào)用棧中彈出,變量都會(huì)被回收。既然變量都被回收了,那么bar.setName()這些調(diào)用方法從何而來(lái)??

foo執(zhí)行完后的情況可以參考下圖:

從上圖可以看出,foo 函數(shù)執(zhí)行完成之后,其執(zhí)行上下文從棧頂彈出了,但是由于返回的 setNamegetName 方法中使用了 foo 函數(shù)內(nèi)部的變量 myNametest1,所以這兩個(gè)變量依然保存在內(nèi)存中。這像極了 setNamegetName 方法背的一個(gè)專屬背包,無(wú)論在哪里調(diào)用了 setName getName 方法,它們都會(huì)背著這個(gè)foo函數(shù)的專屬背包。

之所以是專屬背包,是因?yàn)槌?setNamegetName 函數(shù)之外,其他任何地方都是無(wú)法訪問(wèn)該背包的,我們就可以把這個(gè)背包稱為 foo 函數(shù)的閉包。

好了,現(xiàn)在我們終于可以給閉包一個(gè)正式的定義了。在 JavaScript 中,根據(jù)詞法作用域的規(guī)則,內(nèi)部函數(shù)總是可以訪問(wèn)其外部函數(shù)中聲明的變量,當(dāng)通過(guò)調(diào)用一個(gè)外部函數(shù)返回一個(gè)內(nèi)部函數(shù)后,即使該外部函數(shù)已經(jīng)執(zhí)行結(jié)束了,但是內(nèi)部函數(shù)引用外部函數(shù)的變量依然保存在內(nèi)存中,我們就把這些變量的集合稱為閉包 比如外部函數(shù)是 foo,那么這些變量的集合就稱為 foo 函數(shù)的閉包。

用一句話概括就是

能夠訪問(wèn)其他函數(shù)內(nèi)部變量的函數(shù),被稱為 閉包。

(我們理解可以這么理解,但是和面試官說(shuō)的當(dāng)然可以把這個(gè)例子說(shuō)一下,這直接上升到了一個(gè)理解什么是閉包的新高度了)

到此這篇關(guān)于詳解JavaScript中的作用域鏈與閉包的文章就介紹到這了,更多相關(guān)JavaScript作用域鏈 閉包內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 如何使用50行javaScript代碼實(shí)現(xiàn)簡(jiǎn)單版的call,apply,bind

    如何使用50行javaScript代碼實(shí)現(xiàn)簡(jiǎn)單版的call,apply,bind

    這篇文章主要介紹了50行javaScript代碼實(shí)現(xiàn)簡(jiǎn)單版的call,apply,bind過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • JavaScript?數(shù)組基本操作全解

    JavaScript?數(shù)組基本操作全解

    今天這篇文章就是來(lái)和大家詳細(xì)聊聊JavaScript中數(shù)組的基本操作,很多語(yǔ)言都是在數(shù)組這有個(gè)分水嶺。聽(tīng)懂了接下來(lái)就很容易,聽(tīng)不懂就難辦了,大家要認(rèn)真看喲。希望大家讀完有所收獲,那我辛苦碼字也就值了
    2022-02-02
  • JS基于面向?qū)ο髮?shí)現(xiàn)的拖拽功能示例

    JS基于面向?qū)ο髮?shí)現(xiàn)的拖拽功能示例

    這篇文章主要介紹了JS基于面向?qū)ο髮?shí)現(xiàn)的拖拽功能,涉及javascript面向?qū)ο笈c頁(yè)面元素動(dòng)態(tài)操作的相關(guān)技巧,需要的朋友可以參考下
    2016-12-12
  • 微信小程序連接MySQL數(shù)據(jù)庫(kù)的全過(guò)程

    微信小程序連接MySQL數(shù)據(jù)庫(kù)的全過(guò)程

    微信小程序是不能直接連接數(shù)據(jù)庫(kù)進(jìn)行數(shù)據(jù)操作的,這是出于安全的考慮,下面這篇文章主要給大家介紹了關(guān)于微信小程序連接MySQL數(shù)據(jù)庫(kù)的全過(guò)程,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-01-01
  • JavaScript實(shí)現(xiàn)像雪花一樣的Hexaflake分形

    JavaScript實(shí)現(xiàn)像雪花一樣的Hexaflake分形

    這篇文章主要介紹了JavaScript實(shí)現(xiàn)像雪花一樣的Hexaflake分形,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • IE中鼠標(biāo)經(jīng)過(guò)option觸發(fā)mouseout的解決方法

    IE中鼠標(biāo)經(jīng)過(guò)option觸發(fā)mouseout的解決方法

    這篇文章主要介紹了IE中鼠標(biāo)經(jīng)過(guò)option觸發(fā)mouseout的解決方法,分析了IE中鼠標(biāo)移到option時(shí)window.event.toElement返回值為null的原因及解決方法,需要的朋友可以參考下
    2015-01-01
  • TypeScript中import?type與import的區(qū)別詳析

    TypeScript中import?type與import的區(qū)別詳析

    ES6引入了模塊化,其設(shè)計(jì)思想是在編譯時(shí)就能確定模塊的依賴關(guān)系,以及輸入和輸出的變量,下面這篇文章主要給大家介紹了關(guān)于TypeScript中import?type與import區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • 詳解JavaScript對(duì)象序列化

    詳解JavaScript對(duì)象序列化

    這篇文章主要為大家介紹了JavaScript對(duì)象序列化的相關(guān)資料,需要的朋友可以參考下
    2016-01-01
  • Layui數(shù)據(jù)表格 前后端json數(shù)據(jù)接收的方法

    Layui數(shù)據(jù)表格 前后端json數(shù)據(jù)接收的方法

    今天小編就為大家分享一篇Layui數(shù)據(jù)表格 前后端json數(shù)據(jù)接收的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-09-09
  • 原生javascript AJAX 三級(jí)聯(lián)動(dòng)的實(shí)現(xiàn)代碼

    原生javascript AJAX 三級(jí)聯(lián)動(dòng)的實(shí)現(xiàn)代碼

    這篇文章主要介紹了原生javascript AJAX 三級(jí)聯(lián)動(dòng)的實(shí)現(xiàn)代碼,非常不錯(cuò)代碼簡(jiǎn)單易懂,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-05-05

最新評(píng)論

洛宁县| 平顶山市| 浏阳市| 佛冈县| 建瓯市| 四川省| 云浮市| 柘城县| 平昌县| 怀化市| 大丰市| 永新县| 常熟市| 浦北县| 温泉县| 布尔津县| 南和县| 盐山县| 任丘市| 时尚| 蓝山县| 汽车| 崇州市| 吕梁市| 绥德县| 乌拉特前旗| 偃师市| 凉城县| 上栗县| 城口县| 壶关县| 新蔡县| 揭东县| 桐梓县| 清苑县| 阳高县| 上蔡县| 漯河市| 清苑县| 格尔木市| 巨野县|