作用域和作用域鏈勿侯,閉包

1 作用域

什么是作用域:作用域分為全局作用域和函數(shù)作用域烈炭。全局作用域可以理解為是全局對象(window對象榜掌,GO對象)优妙,而函數(shù)作用域可以理解為是一個函數(shù)內(nèi)部的對象(AO對象)。

全局作用域:所有在script標簽內(nèi)的語句都處在全局作用域中憎账;
頁面打開時創(chuàng)建GO對象套硼,關(guān)閉時銷毀;
定義在全局作用域中的變量胞皱,變量名是GO對象的屬性名邪意,變量值是屬性值。
函數(shù)作用域:所有在函數(shù)體內(nèi)部的語句的處在函數(shù)作用域中反砌;
函數(shù)執(zhí)行時創(chuàng)建AO對象雾鬼,執(zhí)行完畢銷毀AO對象;
函數(shù)作用域中的變量是AO對象的屬性名宴树,變量的值是AO對象的屬性值策菜;
下一次使用函數(shù)時會創(chuàng)建新的AO對象。

1.1語法分析

Js解釋引擎會先掃描所有的js代碼酒贬,查看代碼有沒有低級的語法錯誤又憨,如果存在語法錯誤,則整個程序就不會執(zhí)行,如果沒有語法錯誤锭吨,則進入預解析(編譯)階段

1.2 預編譯

? 全局對象GO
1竟块,創(chuàng)建AO對象 ==> Activation Object(活動對象,作用域,其實叫執(zhí)行期上下文)

2,找到形參和變量耐齐,把形參和變量作為AO對象的屬性名浪秘,值是undefined

3蒋情,實參把值賦給形參

4,在函數(shù)中找到函數(shù)聲明耸携,把函數(shù)名作為AO對象的屬性名棵癣,值是函數(shù)體

       function myTest(a, b) {
            /*
            第一步,AO{ }
            第二步
            AO{
                a:undefined;
                b:undefined;
                c:undefined;
            }
            第三步
            AO{
                a:10;
                b:20;
                c:undefined;
            }
            第四步

            AO{
                a:function() {
                    console.log(100)
                };
                b:20;
                c:undefined;
            }
            
            */
            console.log('a1', a); //f a(){}
            console.log('b1', b); //20
            console.log('c1', c); //undefined
            var c = 30;
            b = 200;

            function a() {
 
            };
            console.log('a2', a); //f a(){}
            console.log('b2', b); //200
            console.log('c2', c); //30
        };
        let result = myTest(10, 20);
        console.log(result);

預編譯后就開始一行一行執(zhí)行代碼夺衍,該改值的改值狈谊。要注意的一點是,這里的c是用var聲明的沟沙,用let和const聲明不會提升河劝,會報錯。

2 作用域鏈

1. 變量查詢規(guī)則

當遇見使用一個變量時矛紫,JS引擎會從其所在的作用域依次向外層查找赎瞎,查找會在找到第一個匹配的標識符的時候停止。(有同名的變量會發(fā)生“遮蔽效應”)

   let a = 1000;

        function myTest() {
            let b = 20;
            outer()
            function outer() {
                let c = 30;
                b = 200;
                console.log(a);//1000
                console.log(b);//200
                inner()
                function inner(){
                    a = 1;
                    console.log(a);//1
                    console.log(c);//30

                }
            }
        }
        let result = myTest();
        console.log(result);

2. 作用域鏈原理理解:

scope翻譯過來就是范圍的意思颊咬。
[[scope]]中所存儲的就是執(zhí)行期上下文對象的集合,這個幾個呈鏈式連接,我們把這種鏈式鏈接叫做作用域鏈务甥。
比方說上述代碼中
myTest


image.png

outer


image.png

inner


image.png

作用域鏈 = 函數(shù)執(zhí)行時的AO對象 + 函數(shù)創(chuàng)建時的環(huán)境。
變量查找規(guī)則:沿著當前函數(shù)作用域鏈作用域鏈頂端喳篇,自上而下尋找變量敞临。

3 閉包

閉包是什么:閉包是指那些引用另一個函數(shù)作用域中變量的函數(shù),通常是在嵌套函數(shù)中實現(xiàn)的麸澜。把一個函數(shù)從它定義的那個作用域挺尿,挪走,運行炊邦。這個函數(shù)能夠記憶住定義時的那個作用域编矾。不管函數(shù)走到哪里,定義時的作用域就帶到了哪里铣耘。這就是閉包洽沟。

上代碼

 function myTest() {
        let count = 0;
        return function inner() {
            console.log(count)
        }
    }
    let  count = 10;
    let inn = myTest();
    let result =  inn()//0

我們都知道以故,inner是定義在myTest內(nèi)蜗细,無法通過inner()直接在全局作用域中直接調(diào)用的;
但這里把inner函數(shù) return出來怒详,執(zhí)行myTest等于返回一個inner函數(shù)炉媒。

  function sum(x,y) {
        return function innerSum(x) {
            return x + y
        }
    }
    let test = sum(3,7);
    test(1)//8,3被8代替了

每次調(diào)用一個函數(shù),都會產(chǎn)生新的閉包.新的閉包知道是,語句全新,所處環(huán)境也是全新的。

        function myTest() {
            let count = 0;
            return function inner() {
                count++;
                return count
            }
        }
        let count = 10;
        let inn1 = myTest();
        let inn2 = myTest();
        inn1();//1
        inn1();//2
        inn1();//3
        inn2();//1

閉包的作用

1,函數(shù)累加器

function outer(){
    var count = 0;
    function inner(){
        count++;
        console.log(count);
    }
    return inner;
}

var inn1 = outer();

inn1(); //1
inn1(); //2 

2,可做緩存

function test(){
    var num = 100;
    function aa(){
        num ++;
        console.log(num);
    }
    function bb(){
        num --;
        console.log(num)
    }
    return [aa,bb]
}
var myArr = test()
myArr[0]()//執(zhí)行num++昆烁,101
myArr[1]() //執(zhí)行num--吊骤,100
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市静尼,隨后出現(xiàn)的幾起案子白粉,更是在濱河造成了極大的恐慌传泊,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸭巴,死亡現(xiàn)場離奇詭異眷细,居然都是意外死亡,警方通過查閱死者的電腦和手機鹃祖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門溪椎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人恬口,你說我怎么就攤上這事校读。” “怎么了祖能?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵歉秫,是天一觀的道長。 經(jīng)常有香客問我芯杀,道長端考,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任揭厚,我火速辦了婚禮却特,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘筛圆。我一直安慰自己裂明,他們只是感情好,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布太援。 她就那樣靜靜地躺著闽晦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪提岔。 梳的紋絲不亂的頭發(fā)上仙蛉,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音碱蒙,去河邊找鬼荠瘪。 笑死,一個胖子當著我的面吹牛赛惩,可吹牛的內(nèi)容都是我干的哀墓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼喷兼,長吁一口氣:“原來是場噩夢啊……” “哼篮绰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起季惯,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤吠各,失蹤者是張志新(化名)和其女友劉穎臀突,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贾漏,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡惧辈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了磕瓷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盒齿。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖困食,靈堂內(nèi)的尸體忽然破棺而出边翁,到底是詐尸還是另有隱情,我是刑警寧澤硕盹,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布符匾,位于F島的核電站,受9級特大地震影響瘩例,放射性物質(zhì)發(fā)生泄漏啊胶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一垛贤、第九天 我趴在偏房一處隱蔽的房頂上張望焰坪。 院中可真熱鬧,春花似錦聘惦、人聲如沸某饰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽黔漂。三九已至,卻和暖如春禀酱,著一層夾襖步出監(jiān)牢的瞬間炬守,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工剂跟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留减途,地道東北人。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓浩聋,卻偏偏與公主長得像观蜗,于是被迫代替她去往敵國和親臊恋。 傳聞我的和親對象是個殘疾皇子衣洁,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容