国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

你不知道的 JavaScript 筆記——作用域和閉包

BearyChat / 1877人閱讀

摘要:理解作用域在引擎看來(lái)是兩個(gè)完全不同的聲明。在循環(huán)中使用閉包閉包是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。回到我們上面說(shuō)的在自己定義的作用域以外的地方執(zhí)行,這里聲明的是全局變量,使用全局變量不構(gòu)成閉包。

第一章:作用域是什么

程序中變量存儲(chǔ)在哪里,需要是怎么找到它,這就需要設(shè)計(jì)一套存儲(chǔ)以及能方便的找到它的規(guī)則,這個(gè)規(guī)則就是作用域

編譯原理

JavaScript 是一門(mén)編譯語(yǔ)言,它與傳統(tǒng)編譯語(yǔ)言不同,但編譯步驟又非常相似;它不是提前編譯的,編譯結(jié)果也不能在分布式系統(tǒng)中進(jìn)行移植。

傳統(tǒng)編譯步驟

分詞 / 詞法分析
將由字符組成的字符串分解成有意義的代碼,例如:var a = 2;通常會(huì)被分解為vara=;這些詞法單元,判斷a是獨(dú)立的詞法單元還是其他詞法單元一部分時(shí),如果調(diào)用的是有狀態(tài)的解析規(guī)則那這個(gè)過(guò)程就是詞法分析

解析 / 語(yǔ)法分析
將詞法單元流(數(shù)組)轉(zhuǎn)換成一個(gè)由元素逐級(jí)嵌套所組成的代表程序語(yǔ)法結(jié)構(gòu)的樹(shù),叫做“抽象語(yǔ)法樹(shù)”(Abstract Syntax Tree,AST)

代碼生成
將 AST 轉(zhuǎn)換為可執(zhí)行代碼的過(guò)程被稱(chēng)為代碼生成。簡(jiǎn)單說(shuō)就是:將var a = 2;的 AST 轉(zhuǎn)化為一組機(jī)器指令,用來(lái)創(chuàng)建一個(gè)a的變量(包括分配內(nèi)存),并將一個(gè)值存儲(chǔ)在a中。

理解作用域

var a = 2;在 JavaScript 引擎看來(lái)是兩個(gè)完全不同的聲明。

遇到var a首先編譯器會(huì)向作用域詢問(wèn)是否有a變量存在這一作用域,如果有就忽略,沒(méi)有就創(chuàng)建a

接下來(lái)處理a = 2這個(gè)賦值操作,先向當(dāng)前作用域詢問(wèn)是否有這個(gè)變量,如果有就使用這個(gè)變量,并賦值;如果沒(méi)有,繼續(xù)找。

LHS查詢 RHS查詢
LHS 賦值操作的目標(biāo)是誰(shuí);RHS 誰(shuí)是賦值操作的源頭(我要查找×××,并把它給我);簡(jiǎn)單說(shuō)如果查找的目的是對(duì)變量進(jìn)行賦值,會(huì)使用 LHS 查詢,如果查找的目的是為了獲取變量值,會(huì)使用 RHS 查詢。
var a = foo(a){...} 這里的聲明,a = ...并不會(huì)做 LHS 查詢。

function foo(a){
  var b = a;
  return a + b;
}
var c = foo(2)
LHS
c = ...
a = 2(隱示變量分配)
b = ...

RHS
foo(...)
= a
a ...
... b
第二章:詞法作用域

詞法作用域是在寫(xiě)代碼時(shí),將變量和塊級(jí)作用域?qū)懺谀睦飦?lái)決定的

詞法階段
function foo(a){
  var b = a * 2;
  function bar(c){
    console.log(a,b,c);        //2,4,12
  }
  bar( b * 3);
}
foo(2);

全局作用域下包含foo

foo作用域下包含abbar

bar作用域下包含c
對(duì)bc的 RHS 查詢是在上一級(jí)作用域中完成的

欺騙詞法

eval()接受一個(gè)字符串作為參數(shù),把它當(dāng)做代碼來(lái)執(zhí)行,在哪個(gè)作用域下調(diào)用它,它的作用域就在哪邊

function foo(str,a){
  eval(str);
  console.log(a,b);        //2,3
}
var b = 2;
foo("var b = 3;",2)

with可以簡(jiǎn)化單調(diào)重復(fù)的賦值操作

var obj ={
  a = 1,
  b = 2,
  c = 3
};
//單調(diào)重復(fù)的賦值
obj.a = 4;
obj.b = 5;
obj.c = 6;
//用with簡(jiǎn)化
with(obj){
  a = 7;
  b = 8;
  c = 9;
}
function foo(obj){
    with(obj){        //相當(dāng)于 obj.a = 2,區(qū)別 with 創(chuàng)建了全局變量 a
        a = 2;
    }
}
var o1 = {
    a:3;
}
var o2 ={
    b:3;
}
foo(o1)
console.log(o1.a)     //2
foo(o2)
console.log(o2.a)    //undefined
console.log(a)        //2

eval()with實(shí)際工作中不推薦使用,會(huì)影響性能。

第三章:函數(shù)作用域和塊作用域 函數(shù)中的作用域

函數(shù)內(nèi)部可以訪問(wèn)函數(shù)外部的變量,函數(shù)外部不可以訪問(wèn)函數(shù)內(nèi)部變量

函數(shù)作用域

函數(shù)的名稱(chēng)也會(huì)污染全局作用域,可以用匿名函數(shù)+立即執(zhí)行函數(shù)來(lái)實(shí)現(xiàn)

立即執(zhí)行函數(shù)

有一個(gè)bug,上一行表達(dá)式必須要分號(hào)結(jié)尾,省略會(huì)報(bào)錯(cuò)

var a = 2;
(function(global){
    var a = 3;
    console.log(a);        //3
    console.log(global.a)    //2
})(window) 
var a = 2;
(function(){
    var a = 3;
    console.log(a);        //3
}())
作用域閉包

1. 在自己定義的作用域以外的地方執(zhí)行
2. 使用回調(diào)函數(shù)也是閉包

function foo(){
  var a = 2
  function bar(){
    console.log(a)
  }
  return bar
}
var baz = foo()
baz() //2  這里就用了閉包

bar是在foo里面定義的,所以它是在foo作用域下,但調(diào)用它的地方是在foo作用域外,就這構(gòu)成了閉包。
在來(lái)看一個(gè)

function foo(){
  var a = 2
  function bar(){
    console.log(a)
  }
  baz(bar)
}
function baz(fn){
  fn()        //2,在這里執(zhí)行了bar,這里構(gòu)成了閉包
}
foo()

還有

var fn 
function foo(){
  var a =2
  function bar(){
    console.log(a)
  }
  fn = baz
}
function baz(){
  fn()
}
foo()
baz()    //2,構(gòu)成了閉包,這里執(zhí)行了 bar,構(gòu)成了閉包。

在循環(huán)中使用閉包
閉包是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。

回到我們上面說(shuō)的:在自己定義的作用域以外的地方執(zhí)行,這里聲明的i是全局變量,使用全局變量不構(gòu)成閉包。

for(var i = 1; i <= 3; i++){
    setTimeout(function(){
        console.log(i)    //打印出 3 個(gè) 4,這里沒(méi)有閉包
    },1000)
}

如果要寫(xiě)成閉包的樣子,必須要在外面用函數(shù)包裹一層,并調(diào)用它,才能形成閉包

function xxx(){
    for(var i = 1; i <= 3; i++){
        setTimeout(function(){
            console.log(i)    //打印出 3 個(gè) 4,這是一個(gè)閉包沒(méi)有立即執(zhí)行
        },1000)
    }
}
xxx()

優(yōu)化1:這里setTimeout里面的i和立即執(zhí)行函數(shù)的形參構(gòu)成閉包,阻隔了與for循環(huán)的i形成閉包。

function xxx(){
    for(var i = 1; i <= 3; i++){
        (function(i){    //這個(gè)形參 i 和外面的 i 不是同一個(gè)變量
            setTimeout(function(){
                console.log(i)    //1,2,3,用立即執(zhí)行函數(shù),
            },1000)
        })(i)
    }
}
xxx()

優(yōu)化2:用let聲明

function xxx(){
    for(let i = 1; i <= 3; i++){
        setTimeout(function(){
            console.log(i)    //1,2,3,用 let 聲明變量,在循環(huán)的過(guò)程中不止一次的聲明
        },1000)
    }
}
xxx()

模塊中閉包
模塊中閉包需要具備兩個(gè)條件:

必須有外部的封閉函數(shù),該函數(shù)至少被調(diào)用一次

封閉函數(shù)至少返回一個(gè)內(nèi)部函數(shù)(可以用 return 或 window)

例:

var foo = function(){
  function a(){
    console.log(1)
  }
  function b(){
    console.log(2)
  }
  return {
    a:a,
    b:b
  }
}
var c = foo()
c.a() //1

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

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

相關(guān)文章

  • 重讀你不知道JS (上) 第一節(jié)五章

    摘要:詞法作用域的查找規(guī)則是閉包的一部分。因此的確同閉包息息相關(guān),即使本身并不會(huì)真的使用閉包。而上面的創(chuàng)建一個(gè)閉包,本質(zhì)上這是將一個(gè)塊轉(zhuǎn)換成一個(gè)可以被關(guān)閉的作用域。結(jié)合塊級(jí)作用域與閉包模塊這個(gè)模式在中被稱(chēng)為模塊。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門(mén)充滿吸引力、簡(jiǎn)單易用的語(yǔ)言,又是一門(mén)具有許多復(fù)雜微妙技術(shù)的語(yǔ)言,即使是經(jīng)驗(yàn)豐富的 Jav...

    worldligang 評(píng)論0 收藏0
  • 你不知道JavaScript上卷之作用域與閉包·讀書(shū)筆記

    摘要:的分句會(huì)創(chuàng)建一個(gè)塊作用域,其聲明的變量?jī)H在中有效。而閉包的神奇作用是阻止此事發(fā)生。依然持有對(duì)該作用域的引用,而這個(gè)引用就叫做閉包。當(dāng)然,無(wú)論使用何種方式對(duì)函數(shù)類(lèi)型的值進(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 (上) 第一節(jié)三章

    摘要:如果是聲明中的第一個(gè)詞,那么就是一個(gè)函數(shù)聲明,否則就是一個(gè)函數(shù)表達(dá)式。給函數(shù)表達(dá)式指定一個(gè)函數(shù)名可以有效的解決以上問(wèn)題。始終給函數(shù)表達(dá)式命名是一個(gè)最佳實(shí)踐。也有開(kāi)發(fā)者干脆關(guān)閉了靜態(tài)檢查工具對(duì)重復(fù)變量名的檢查。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門(mén)充滿吸引力、簡(jiǎn)單易用的語(yǔ)言,又是一門(mén)具有許多復(fù)雜微妙技術(shù)的語(yǔ)言,即使是經(jīng)驗(yàn)豐富的 Ja...

    lavor 評(píng)論0 收藏0
  • [JS]《你不知道Javascript·上》——詞法作用域和閉包

    摘要:吐槽一下,閉包這個(gè)詞的翻譯真是有很大的誤解性啊要說(shuō)閉包,要先說(shuō)下詞法作用域。閉包兩個(gè)作用通過(guò)閉包,在外部環(huán)境訪問(wèn)內(nèi)部環(huán)境的變量。閉包使得函數(shù)可以繼續(xù)訪問(wèn)定義時(shí)的詞法作用域。 閉包是真的讓人頭暈啊,看了很久還是覺(jué)得很模糊。只能把目前自己的一些理解先寫(xiě)下來(lái),這其中必定包含著一些錯(cuò)誤,待日后有更深刻的理解時(shí)再作更改。 吐槽一下,閉包這個(gè)詞的翻譯真是有很大的誤解性啊…… 要說(shuō)閉包,要先說(shuō)下詞法...

    guqiu 評(píng)論0 收藏0
  • 重讀你不知道JS (上) 第一節(jié)四章

    摘要:如果提升改變了代碼執(zhí)行的順序,會(huì)造成非常嚴(yán)重的破壞。聲明本身會(huì)被提升,而包括函數(shù)表達(dá)式的賦值在內(nèi)的賦值操作并不會(huì)提升。要注意避免重復(fù)聲明,特別是當(dāng)普通的聲明和函數(shù)聲明混合在一起的時(shí)候,否則會(huì)引起很多危險(xiǎn)的問(wèn)題 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門(mén)充滿吸引力、簡(jiǎn)單易用的語(yǔ)言,又是一門(mén)具有許多復(fù)雜微妙技術(shù)的語(yǔ)言,即使是經(jīng)驗(yàn)豐富的 Ja...

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

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

0條評(píng)論

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