成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Js基礎(chǔ)知識(shí)(三) - 作用域與閉包

lemanli / 2410人閱讀

摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內(nèi)部,也就是說(shuō)為其聲明的變量隱式的劫持了所在的塊級(jí)作用域。

作用域與閉包
如何用js創(chuàng)建10個(gè)button標(biāo)簽,點(diǎn)擊每個(gè)按鈕時(shí)打印按鈕對(duì)應(yīng)的序號(hào)?

看到上述問(wèn)題,如果你能看出來(lái)這個(gè)問(wèn)題實(shí)質(zhì)上是考對(duì)作用域的理解,那么恭喜你,這篇文章你可以不用看了,說(shuō)明你對(duì)作用域已經(jīng)理解的很透徹了,但是如果你看不出來(lái)這是一道考作用域的題目,那么請(qǐng)看下文...

工作模式

在所有的語(yǔ)言中,作用域一般有兩種主要的工作模式:詞法作用域和動(dòng)態(tài)作用域。詞法作用域就是定義在詞法階段的作用域,是由寫(xiě)代碼時(shí)將變量和塊作用域?qū)懺谀睦飦?lái)決定的,不會(huì)改變。而動(dòng)態(tài)作用域并不關(guān)心函數(shù)和作用域是如何聲明以及在任何處聲明的,只關(guān)心它們從何處調(diào)用。javascript是詞法作用域工作模式。 看下面的例子體會(huì)一下:

function static () {
    var foo=1
    alert(foo)         
}      
!function () {
    var foo=2
    static(); // 如果是詞法作用域會(huì)打印1,如果是動(dòng)態(tài)作用域則打印2   
}();
作用域

在es6之前javascript的作用域只有全局作用域和局部作用域(函數(shù)作用域),是沒(méi)有塊級(jí)作用域的。在es6中提供了let,可以簡(jiǎn)單的定義一個(gè)塊級(jí)作用域變量。使用let可以將變量綁定在所在的任意作用域中(通常是{...}內(nèi)部),也就是說(shuō)let為其聲明的變量隱式的劫持了所在的塊級(jí)作用域。
為了方便理解作用域,需要知道下面幾個(gè)概念:

自由變量:當(dāng)前作用域沒(méi)有的變量就稱(chēng)為自由變量

作用域鏈:當(dāng)前作用域沒(méi)定義的變量(自由變量),會(huì)逐級(jí)向父級(jí)作用域?qū)ふ?/p>

父級(jí)作用域: 哪個(gè)作用域定義了當(dāng)前作用域,那就是當(dāng)前作用域的父級(jí)作用域

var a = 1
function foo () {
    alert(a) // 在foo函數(shù)作用域中a就是自由變量,因?yàn)樵趂oo中沒(méi)有定義a,便向父級(jí)作用域(此為全局作用域)查找
}
作用域提升

關(guān)于作用域提升與js引擎線程運(yùn)行原理有關(guān),js引擎運(yùn)行時(shí)會(huì)執(zhí)行三步操作,第一步是先檢查你的js代碼有沒(méi)有低級(jí)的語(yǔ)法錯(cuò)誤,第二步是預(yù)編譯,第三步是根據(jù)代碼順序解釋一句執(zhí)行一句。

第一步和第三步都很好理解,重點(diǎn)解釋一下第二步預(yù)編譯,所謂預(yù)編譯就是在執(zhí)行代碼會(huì)把所有的變量聲明和函數(shù)聲明預(yù)先處理。當(dāng)你寫(xiě)了一句var a = 1時(shí),javascript會(huì)當(dāng)成兩個(gè)操作:var a;和a = 1;第一個(gè)是在預(yù)編譯中執(zhí)行的,此時(shí)只是聲明了a這個(gè)變量,沒(méi)有賦值操作,所以此階段a的值為undefined。
正是因?yàn)轭A(yù)編譯存在,所以javascript會(huì)存在作用域變量提升??聪旅娴睦涌梢愿玫睦斫猓?/p>

console.log(a) // undefined
var a = 1

//上述代碼可以這樣理解
var a // 此時(shí)a的值為undefined
console.log(a)
a = 1

變量提升有兩點(diǎn)需要記住:

只有聲明才會(huì)被提升

foo()
foo =  function() { // 這里只是賦值表達(dá)式,不會(huì)被提升
    console.log(1)
}
function foo() { // 以function開(kāi)頭定義的函數(shù)才是聲明,會(huì)被提升
    console.log(2)
}

// 可以這樣理解

function foo() {
    console.log(2)
}
foo() // 2
foo =  function() {
    console.log(1)
}

每個(gè)作用域都會(huì)提升,提升到當(dāng)前作用域

foo()
function foo () {
    console.log(a) // undefinded
    var a = 1
}

//可以這樣理解

function foo () {
    var a // undefined
    console.log(a)
    a = 1
}
foo()
閉包

對(duì)于閉包的定義,各種說(shuō)法都有,在KYLE SIMPSON著的《你不知道的javascript》中是這樣定義的:當(dāng)函數(shù)可以記住并訪問(wèn)所在的詞法作用域時(shí),就產(chǎn)生了閉包,即使函數(shù)是在當(dāng)前此法作用域之外執(zhí)行。

還有網(wǎng)絡(luò)上不同版本的定義,還有的說(shuō)在函數(shù)中定義函數(shù),并返回函數(shù),就是閉包。其實(shí)都差不多,各個(gè)版本都有一定的道理,但也不一定全對(duì),因?yàn)槟壳斑€沒(méi)有一個(gè)完美的、得到廣泛認(rèn)可的公認(rèn)的定義。所以這里我們對(duì)閉包的定義也不便做更多的解釋。如果你覺(jué)得有一個(gè)概念定義會(huì)對(duì)你理解閉包有幫助,我比較推薦《你不知道的javascript》中對(duì)閉包的定義。

從下面一個(gè)小例子先來(lái)認(rèn)識(shí)一下閉包:

function foo () {
    var a = 1
    function fn() {
        console.log(a)
    }
    return fn()
}
var bar = foo()
bar() // 1

上述就是一個(gè)簡(jiǎn)單的閉包的例子,fn函數(shù)可以被執(zhí)行,并且是在fn函數(shù)被定義的詞法作用域的外面執(zhí)行。

通常由于js引擎的垃圾回收機(jī)制,一個(gè)普通的函數(shù)在執(zhí)行之后內(nèi)部作用域以及內(nèi)部變量會(huì)被銷(xiāo)毀,垃圾機(jī)制用來(lái)回收釋放不再使用內(nèi)存空間。

正常來(lái)說(shuō),當(dāng)foo執(zhí)行之后,foo函數(shù)內(nèi)部作用域會(huì)被銷(xiāo)毀,但是閉包就會(huì)阻止垃圾回收,事實(shí)上內(nèi)部作用域還存在,因?yàn)閒n函數(shù)還在使用使用foo函數(shù)的內(nèi)部作用域。

到現(xiàn)在為止應(yīng)該對(duì)閉包有個(gè)初步的認(rèn)識(shí)了,下面就來(lái)回過(guò)頭去看看最開(kāi)始預(yù)留的問(wèn)題:如何用js創(chuàng)建10個(gè)button標(biāo)簽,點(diǎn)擊每個(gè)按鈕時(shí)打印按鈕對(duì)應(yīng)的序號(hào)?

先看一個(gè)錯(cuò)誤的示例:

var i = 1
for (i=1;i<=10;i++){
    var btn = document.createElement("BUTTON")
    btn.innerHTML = i
    btn.addEventListener("click",function(event){
        alert(i)
    })
    document.getElementById("div").appendChild(btn)
}

大家可以把上面的代碼測(cè)試一下,你會(huì)發(fā)現(xiàn)屏幕上出現(xiàn)了10個(gè)按鈕,序號(hào)從0到9,但是當(dāng)你點(diǎn)擊每一個(gè)按鈕的時(shí)候發(fā)現(xiàn)都是彈出11,這是因?yàn)楫?dāng)你點(diǎn)擊按鈕的時(shí)候for循環(huán)早已經(jīng)執(zhí)行完畢,這時(shí)i的值已經(jīng)變成11,當(dāng)點(diǎn)擊執(zhí)行到alert(i)的時(shí)候,發(fā)現(xiàn)當(dāng)前作用域沒(méi)有i,便去父作用域?qū)ふ襥,這時(shí)i的值為11,所以會(huì)打印出11。

那么應(yīng)該怎樣才能達(dá)到我們想要的效果呢,我們知道IIFE函數(shù)其實(shí)也是普通函數(shù),既然是函數(shù)就可以可以有自己的作用域,不妨利用IIFE函數(shù)來(lái)試試:

var i = 1
for (i=1;i<=10;i++){
    (function(num){
        var btn = document.createElement("BUTTON")
        btn.innerHTML = num
        btn.addEventListener("click",function(event){
            alert(num)
        })
        document.getElementById("div").appendChild(btn)
    })(i)    
}

每次循環(huán)創(chuàng)建一個(gè)IIFE函數(shù),每個(gè)IIFE函數(shù)都有自己的局部作用域,這里通過(guò)向IIFE函數(shù)傳值的方式在IIFE函數(shù)中創(chuàng)建局部變量num,每一個(gè)IIFE函數(shù)都有自己的num變量,這樣在點(diǎn)擊執(zhí)行alert(num)的時(shí)候就會(huì)在當(dāng)前作用域找到num。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/115610.html

相關(guān)文章

  • Js基礎(chǔ)知識(shí)) - 作用域與閉包

    摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內(nèi)部,也就是說(shuō)為其聲明的變量隱式的劫持了所在的塊級(jí)作用域。 作用域與閉包 如何用js創(chuàng)建10個(gè)button標(biāo)簽,點(diǎn)擊每個(gè)按鈕時(shí)打印按鈕對(duì)應(yīng)的序號(hào)? 看到上述問(wèn)題,如果你能看出來(lái)這個(gè)問(wèn)題實(shí)質(zhì)上是考對(duì)作用域的理解,那么恭喜你,這篇文章你可以不用看了,說(shuō)明你對(duì)作用域已經(jīng)理解的很透徹了,但是如果你看不出來(lái)這是一道考作用域的題目,...

    XFLY 評(píng)論0 收藏0
  • Js基礎(chǔ)知識(shí)) - 作用域與閉包

    摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內(nèi)部,也就是說(shuō)為其聲明的變量隱式的劫持了所在的塊級(jí)作用域。 作用域與閉包 如何用js創(chuàng)建10個(gè)button標(biāo)簽,點(diǎn)擊每個(gè)按鈕時(shí)打印按鈕對(duì)應(yīng)的序號(hào)? 看到上述問(wèn)題,如果你能看出來(lái)這個(gè)問(wèn)題實(shí)質(zhì)上是考對(duì)作用域的理解,那么恭喜你,這篇文章你可以不用看了,說(shuō)明你對(duì)作用域已經(jīng)理解的很透徹了,但是如果你看不出來(lái)這是一道考作用域的題目,...

    tanglijun 評(píng)論0 收藏0
  • Js基礎(chǔ)知識(shí)) - 作用域與閉包

    摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內(nèi)部,也就是說(shuō)為其聲明的變量隱式的劫持了所在的塊級(jí)作用域。 作用域與閉包 如何用js創(chuàng)建10個(gè)button標(biāo)簽,點(diǎn)擊每個(gè)按鈕時(shí)打印按鈕對(duì)應(yīng)的序號(hào)? 看到上述問(wèn)題,如果你能看出來(lái)這個(gè)問(wèn)題實(shí)質(zhì)上是考對(duì)作用域的理解,那么恭喜你,這篇文章你可以不用看了,說(shuō)明你對(duì)作用域已經(jīng)理解的很透徹了,但是如果你看不出來(lái)這是一道考作用域的題目,...

    lmxdawn 評(píng)論0 收藏0
  • 《你不知道的javascript》筆記_作用域與閉包

    摘要:建筑的頂層代表全局作用域。實(shí)際的塊級(jí)作用域遠(yuǎn)不止如此塊級(jí)作用域函數(shù)作用域早期盛行的立即執(zhí)行函數(shù)就是為了形成塊級(jí)作用域,不污染全局。這便是閉包的特點(diǎn)吧經(jīng)典面試題下面的代碼輸出內(nèi)容答案?jìng)€(gè)如何處理能夠輸出閉包方式方式下一篇你不知道的筆記 下一篇:《你不知道的javascript》筆記_this 寫(xiě)在前面 這一系列的筆記是在《javascript高級(jí)程序設(shè)計(jì)》讀書(shū)筆記系列的升華版本,旨在將零碎...

    galaxy_robot 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<