成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

《你不知道的JS》讀書(shū)筆記---作用域及閉包

denson / 3491人閱讀

摘要:注此讀書(shū)筆記只記錄本人原先不太理解的內(nèi)容經(jīng)過(guò)閱讀你不知道的后的理解。作用域及閉包基礎(chǔ),代碼運(yùn)行的幕后工作者引擎及編譯器。

注:此讀書(shū)筆記只記錄本人原先不太理解的內(nèi)容經(jīng)過(guò)閱讀《你不知道的JS》后的理解。
作用域及閉包基礎(chǔ),JS代碼運(yùn)行的幕后工作者:引擎及編譯器。引擎負(fù)責(zé)JS程序的編譯及執(zhí)行,編譯器負(fù)責(zé)詞法分析和代碼生成。那么作用域就像一個(gè)容器,引擎及編譯器都從這里提取東西。
如 var a = 2 這句簡(jiǎn)單的代碼,聲明一個(gè)變量a,同時(shí)給他賦值為2.
背后運(yùn)行的過(guò)程,編譯器階段:
進(jìn)行詞法分析,將證據(jù)代碼切分成 var, a, =, 2 并逐一分析是否有特定作用,詞法分析的過(guò)程中遇到var a 會(huì)詢問(wèn)作用域在當(dāng)前作用域下是否有a這個(gè)變量,若有,則忽略聲明,繼續(xù)編譯,若無(wú),就要求作用域在當(dāng)前作用域聲明該變量。 而后生成 var a = 2的代碼。
引擎階段:運(yùn)行var a =2 時(shí) 首先訪問(wèn)當(dāng)前作用域是否有a 的變量,有就賦值為2,沒(méi)有就向上查詢。若最終能找到該變量則使用該變量并給它賦值為2,若沒(méi)有就會(huì)拋出一個(gè)異常。
以上就是其背后的運(yùn)行過(guò)程。

塊作用域:
JS語(yǔ)言中似乎是沒(méi)有相對(duì)其他語(yǔ)言相關(guān)的塊作用域的說(shuō)法即{}框定的內(nèi)容不算一個(gè)封閉的作用域,簡(jiǎn)單的例子:

if(true){
    var b = "this is in the block"
}

console.log(b) //this is in the block

顯然b變量在if的語(yǔ)句塊外獲取到了,有如下幾種做法可以限定作用域:
let, IIFE(立即執(zhí)行函數(shù)表達(dá)式)[相當(dāng)于變成了函數(shù)作用域], with
但是用with的時(shí)候需要注意:
簡(jiǎn)單的例子

var ob1 = {
    a : 1
}

var ob2 = {
    b : 2
}

with(ob1) {
    a = 2
}
with(ob2) {
    a = 1
}
ob1.a // 2
ob2.a //undefined
a // 1





發(fā)現(xiàn)在ob2里面還是無(wú)法找到a的屬性,同時(shí)全局變量多了個(gè)a變量賦值為了1,這里的原理是在ob2的作用域中LHS尋找a變量,并沒(méi)有找到,則會(huì)創(chuàng)建一個(gè)屬于全局作用域的a變量(非嚴(yán)格模式)[這是硬知識(shí),不知道其這樣實(shí)現(xiàn)的原理是什么]。所以可以在全局環(huán)境中找到a這個(gè)變量,其值為1.原理跟下述的例子類似:

function foo(){
    var a = 1
    b = a // 這里函數(shù)作用域中b變量是未聲明的,編譯器在進(jìn)行LHS查詢時(shí)由于未能在所有的作用域中找到b‘
          //,(非嚴(yán)格模式下)會(huì)自動(dòng)聲明一個(gè)全局變量
    something
    return something
}

就像上述的例子,只不過(guò)是換了個(gè)對(duì)象而已,由ob2換成了foo函數(shù)對(duì)象。

閉包
閉包是一個(gè)極其有意思的現(xiàn)象,官方的解釋是這樣的,函數(shù)在其所在的作用域外被調(diào)用,同時(shí)該函數(shù)訪問(wèn)了其作用域中的某些變量,這就形成了一個(gè)閉包。

一個(gè)簡(jiǎn)單的例子:

function closure(){
    var a = "here is closure"
    function out(){
        console.log(a)
    }
    return out
}

var test = closure()
a = "here is out of closure"
test() // "here is closure"

這里輸出的是"here is closure",分析下代碼:

var test = closure() //  var test = function(){
                     //             console.log(a)
                     //  }
a = "here is out of closure"
test()

理論上來(lái)說(shuō),按照作用域的概念,這里應(yīng)該輸出的是上一句的a變量,這里test的函數(shù)無(wú)法訪問(wèn)到closure內(nèi)部的變量的。這就是閉包的作用,我的理解是,他會(huì)將作用域給鎖定,內(nèi)存中原函數(shù)的內(nèi)部的變量并不會(huì)被回收。因此在函數(shù)在其作用域外被調(diào)用,還是能使用其作用域中的變量a.

利用閉包這個(gè)特性,JS還有很多有意思的東西:
下面這個(gè)比較通俗點(diǎn)的例子,廖學(xué)峰大佬的JS教程中的例子:

   function count() {
        var arr = [];
        for (var i=1; i<=3; i++) {
            arr.push(function () {
                return i * i;
            });
        }
        return arr;
    }
    
    var array = count()
    var f1 = array[0]
    var f2 = array[1]
    var f3 = array[2]
    f1()  // 16
    f2()  // 16
    f3()  // 16
    
    

預(yù)期的輸出應(yīng)該是1, 4, 9,但實(shí)際的結(jié)果是全都是16,原因就在于JS的for循環(huán)沒(méi)有塊作用域這個(gè)屬性,數(shù)組添加元素的內(nèi)容是一個(gè)函數(shù),而函數(shù)并非立即調(diào)用,他們都共享一個(gè)作用域,而作用域中的變量i只有一個(gè),其最終的結(jié)果就是4,所以所有的輸出都是16。

要解決這個(gè)問(wèn)題,可以用快作用域的方法,let, IIFE將i在迭代時(shí)的作用域鎖定。

 function count() {
        var arr = [];
        for (var i=1; i<=3; i++) {
            (function(){
                var j = i  //利用IIFE時(shí)需要聲明變量接受變量i,否則IIFE中的作用域?yàn)榭眨蛏喜樵?,使?               
                          //的仍然是i,而全局共享的i依舊取最終的結(jié)果
                arr.push(function () {
                             return j * j;
                        });
            })()
        }
        return arr;
    }
    
    var array = count()
    var f1 = array[0]
    var f2 = array[1]
    var f3 = array[2]
    f1()  // 1
    f2()  // 4
    f3()  // 9

這里的上下兩個(gè)例子都是閉包的例子,不同的是,第一個(gè)閉包的訪問(wèn)的作用域是函數(shù)count的內(nèi)部作用域共享一個(gè)變量i,取最后的值,而下一個(gè)例子,閉包訪問(wèn)的作用域是一個(gè)IIFE的內(nèi)部作用域,為變量j。而IIFE是類似一個(gè)函數(shù)作用域,j是不會(huì)隨著i變化而變化,這里執(zhí)行了3次IIFE,每次的IIFE對(duì)應(yīng)的變量j是不同的,不會(huì)相互影響,所以達(dá)到了預(yù)期輸出,如果IIFE中作用域?yàn)榭?,那么閉包訪問(wèn)的仍舊是count的作用域,因此依舊達(dá)不到期望的輸出。

同理let也能達(dá)到預(yù)期的輸出

 function count() {
        var arr = [];
        for (var i=1; i<=3; i++) {
                let j = i  
                arr.push(function () {
                             return j * j;
                        });
        }
        return arr;
    }
    
    var array = count()
    var f1 = array[0]
    var f2 = array[1]
    var f3 = array[2]
    f1()  // 1
    f2()  // 4
    f3()  // 9

而for循環(huán)結(jié)構(gòu)有個(gè)特殊的地方,for 循環(huán)頭部的 let 聲明還會(huì)有一
個(gè)特殊的行為。這個(gè)行為指出變量在循環(huán)過(guò)程中不止被聲明一次,每次迭代都會(huì)聲明。隨
后的每個(gè)迭代都會(huì)使用上一個(gè)迭代結(jié)束時(shí)的值來(lái)初始化這個(gè)變量。
所以還可以這樣實(shí)現(xiàn),使代碼結(jié)構(gòu)更為明朗:

function count() {
        var arr = [];
        for (let i=1; i<=3; i++) {
                arr.push(function () {
                             return i * i;
                        });
        }
        return arr;
    }
    
    var array = count()
    var f1 = array[0]
    var f2 = array[1]
    var f3 = array[2]
    f1()  // 1
    f2()  // 4
    f3()  // 9

以上就是對(duì)當(dāng)初作用域不太理解的地方如今通過(guò)此書(shū)獲得的認(rèn)識(shí),以上只是個(gè)人的理解,依舊存有疑問(wèn),如為什么在IIFE實(shí)現(xiàn)獨(dú)立作用域的時(shí)候若不聲明var j = i或獲得的結(jié)果依舊不是期望的值,是因?yàn)殚]包在當(dāng)前作用域訪問(wèn)不到i的時(shí)候,訪問(wèn)了上一級(jí)的作用域,同時(shí)將這個(gè)作用域保存在了作用域鏈中嗎?

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/90400.html

相關(guān)文章

  • 你不知道JavaScript上卷之作用域與閉包·讀書(shū)筆記

    摘要:的分句會(huì)創(chuàng)建一個(gè)塊作用域,其聲明的變量?jī)H在中有效。而閉包的神奇作用是阻止此事發(fā)生。依然持有對(duì)該作用域的引用,而這個(gè)引用就叫做閉包。當(dāng)然,無(wú)論使用何種方式對(duì)函數(shù)類型的值進(jìn)行傳遞,當(dāng)函數(shù)在別處被調(diào)用時(shí)都可以觀察到閉包。 date: 16.12.8 Thursday 第一章 作用域是什么 LHS:賦值操作的目標(biāo)是誰(shuí)? 比如: a = 2; RHS:誰(shuí)是賦值操作的源頭? 比如: conso...

    Raaabbit 評(píng)論0 收藏0
  • 你不知道JS讀書(shū)筆記閉包在循環(huán)中應(yīng)用

    摘要:閉包在循環(huán)中的應(yīng)用延遲函數(shù)的回調(diào)會(huì)在循環(huán)結(jié)束時(shí)才執(zhí)行事實(shí)上,當(dāng)定時(shí)器運(yùn)行時(shí)即使沒(méi)給迭代中執(zhí)行的是多有的回調(diào)函數(shù)依然是在循環(huán)結(jié)束后才會(huì)被執(zhí)行,因此會(huì)每次輸出一個(gè)出來(lái)。 閉包在循環(huán)中的應(yīng)用 延遲函數(shù)的回調(diào)會(huì)在循環(huán)結(jié)束時(shí)才執(zhí)行;事實(shí)上,當(dāng)定時(shí)器運(yùn)行時(shí)即使沒(méi)給迭代中執(zhí)行的是 setTime(..., 0),多有的回調(diào)函數(shù)依然是在循環(huán)結(jié)束后才會(huì)被執(zhí)行,因此會(huì)每次輸出一個(gè)6出來(lái)。 for(var...

    weapon 評(píng)論0 收藏0
  • 讀書(shū)筆記-你不知道JavaScript(上)

    摘要:比如程序會(huì)被分解為解析語(yǔ)法分析將詞法單元流轉(zhuǎn)換成一個(gè)由元素逐級(jí)嵌套所組成的代表了程序語(yǔ)法接口的書(shū),又稱抽象語(yǔ)法樹(shù)。代碼生成將抽象語(yǔ)法樹(shù)轉(zhuǎn)換為機(jī)器能夠識(shí)別的指令。 showImg(https://segmentfault.com/img/remote/1460000009682106?w=640&h=280); 本文首發(fā)在我的個(gè)人博客:http://muyunyun.cn/ 《你不知道的...

    jzzlee 評(píng)論0 收藏0
  • 你不知道JavaScript》 (上) 閱讀摘要

    摘要:但是如果非全局的變量如果被遮蔽了,無(wú)論如何都無(wú)法被訪問(wèn)到。但是如果引擎在代碼中找到,就會(huì)完全不做任何優(yōu)化。結(jié)構(gòu)的分句中具有塊級(jí)作用域。第四章提升編譯器函數(shù)聲明會(huì)被提升,而函數(shù)表達(dá)式不會(huì)被提升。 本書(shū)屬于基礎(chǔ)類書(shū)籍,會(huì)有比較多的基礎(chǔ)知識(shí),所以這里僅記錄平常不怎么容易注意到的知識(shí)點(diǎn),不會(huì)全記,供大家和自己翻閱; 上中下三本的讀書(shū)筆記: 《你不知道的JavaScript》 (上) 讀書(shū)筆記...

    FingerLiu 評(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)論

閱讀需要支付1元查看
<