2018-12-18


JS高級(jí)

作用域&作用域鏈

作用域:

1.作用域的個(gè)數(shù):n(函數(shù)聲明的個(gè)數(shù))+1(全局作用域)
2.作用域不會(huì)存儲(chǔ)變量,只是執(zhí)行查詢規(guī)則
3.作用域分全局作用域和函數(shù)(局部)作用域
4.作用域是編譯時(shí)產(chǎn)生的
5.沒有塊作用域(ES5)
6.作用域管理執(zhí)行上下文,執(zhí)行上下文管理變量
7.一般情況下,一個(gè)作用域?qū)?yīng)一個(gè)執(zhí)行上下文,但遞歸情況下一個(gè)作用域可以對(duì)應(yīng)多個(gè)執(zhí)行上下文。值得注意的是,任何情況下一個(gè)作用域只有一個(gè)活動(dòng)的執(zhí)行上下文

作用域鏈:

函數(shù)嵌套時(shí)會(huì)產(chǎn)生作用域鏈

--
作用域的作用:
1.隔離變量
2.為變量查詢制定的一套規(guī)則。
--
變量查詢的規(guī)則:
左查詢:等號(hào)左邊的變量用左查詢。
--先在變量的當(dāng)前作用域里面找變量是否聲明,沒有就到上一層找,直到整條作用域鏈都沒有找到(也就是全局),那么瀏覽器會(huì)自動(dòng)為變量聲明。
右查詢:等號(hào)非左邊的變量用右查詢規(guī)則。
--先在變量的當(dāng)前作用域里面找變量是否聲明,沒有就到上一層找,直到整條作用域鏈都沒有找到(也就是全局),那么報(bào)錯(cuò)。
--
左右查詢案例:

<script>
        console.log(b); // 報(bào)錯(cuò)
        (function(){
            function test(a){
                var b=a;
                console.log(b);//2
            }
            test(2);
        })()
        console.log(b);//b is not defined
</script>

執(zhí)行步驟:
1.console.log(b); 對(duì)b右查詢,在當(dāng)前作用域(全局)查找b的聲明,沒有則報(bào)錯(cuò)
2.執(zhí)行立即執(zhí)行函數(shù),然后調(diào)用test(2)函數(shù),將實(shí)參2傳給形參a
3.var b=a;對(duì)b執(zhí)行左查詢,在當(dāng)前作用域有聲明var b,且b=a,則b為2,輸出2
4.立即執(zhí)行函數(shù)運(yùn)行結(jié)束, 運(yùn)行console.log(b);對(duì)b進(jìn)行右查詢,在當(dāng)前作用域(全局)查找b的聲明,整條作用域鏈上沒有找到,則報(bào)錯(cuò)。


作用域面試題:


image.png

以上示例圖的執(zhí)行步驟:
1.先執(zhí)行var x =10;(x為全局變量)
2.執(zhí)行show(fn);調(diào)用show()函數(shù),將實(shí)參fn函數(shù)傳給形參f,那么形參f擁有fn函數(shù)的地址值
3.f(),調(diào)用fn()函數(shù)。
4.console.log(x);對(duì)x執(zhí)行右查詢,在fn()函數(shù)中沒有對(duì)變量x進(jìn)行聲明,那么到全局作用域里面去找,剛好找到var x =10;所以結(jié)果為10.


變量釋放&內(nèi)存回收

變量釋放:
局部變量————>對(duì)應(yīng)函數(shù)的作用域執(zhí)行完后則變量釋放
全局變量————>當(dāng)運(yùn)行程序關(guān)閉時(shí)變量才會(huì)釋放
內(nèi)存回收:
垃圾收集器會(huì)按照固定的時(shí)間間隔周期性的回收內(nèi)存。一般使用標(biāo)記清除,引用計(jì)數(shù)兩種策略。


執(zhí)行上下文&執(zhí)行上下文棧

執(zhí)行上下文(可以認(rèn)為是可執(zhí)行代碼的執(zhí)行環(huán)境):
1.執(zhí)行上下文的個(gè)數(shù):n(函數(shù)的調(diào)用次數(shù))+1(全局執(zhí)行上下文)
2.在函數(shù)被調(diào)用時(shí),都會(huì)創(chuàng)建新的其對(duì)應(yīng)作用域的執(zhí)行上下文。
3.一般情況下,一個(gè)作用域?qū)?yīng)一個(gè)執(zhí)行上下文,但遞歸時(shí),一個(gè)作用域可能對(duì)應(yīng)多個(gè)執(zhí)行上下文。(每調(diào)用一次函數(shù)創(chuàng)建一個(gè)執(zhí)行上下文)
4.一個(gè)作用域只能有一個(gè)活動(dòng)狀態(tài)的執(zhí)行上下文。(單線程、同步執(zhí)行)
5.執(zhí)行上下文分為:全局執(zhí)行上下文(只有一個(gè))、函數(shù)執(zhí)行上下文(可以有無數(shù)個(gè))
--
執(zhí)行上下文棧:
當(dāng)一個(gè)函數(shù)被調(diào)用時(shí),會(huì)創(chuàng)建一個(gè)當(dāng)前被調(diào)用函數(shù)的執(zhí)行上下文,并將執(zhí)行上下文壓入執(zhí)行棧中。當(dāng)js第一次加載腳本時(shí),默認(rèn)進(jìn)入全局執(zhí)行上下文中。


image.png
<!--
    1. 依次輸出什么?
    2. 整個(gè)過程中產(chǎn)生了幾個(gè)執(zhí)行上下文?
-->
<script type="text/javascript">
  var i
  console.log('global begin: '+ i)   //undefined
  i = 1
  foo(1);
  function foo(i){
    if (i == 4) {
      return;
    }
    console.log('foo() begin:' + i);    //1,2,3
    foo(i + 1);
    console.log('foo() end:' + i);     //3,2,1                                    
  }
   console.log('global end: ' + i)     //1
</script>
image.png

執(zhí)行上下文的作用:

1.存儲(chǔ)對(duì)應(yīng)的變量
2.規(guī)則
---全局執(zhí)行上下文規(guī)則:
1.var定義的全局變量,添加為window的屬性
2.function聲明的全局函數(shù),添加為window的方法
3.提升(函數(shù)的提升優(yōu)于變量的提升)
4.this指向(window)
--
---函數(shù)執(zhí)行上下文規(guī)則
1.var定義的局部變量會(huì)成為局部執(zhí)行上下文(在js中拿不到局部執(zhí)行上下文對(duì)象)的屬性
2.function聲明的局部函數(shù)會(huì)成為局部執(zhí)行上下文(在js中拿不到局部上下文對(duì)象)的方法
3.形參變量賦值給實(shí)參
4.為arguments賦值(實(shí)參列表)
5.提升(函數(shù)表達(dá)式不會(huì)提升)
6.this指向(看調(diào)用函數(shù)的對(duì)象的調(diào)用形式)
--
---函數(shù)執(zhí)行上下文規(guī)則的this指向
1.普通調(diào)用??????this—>window
???在嚴(yán)格模式下 this—>undefined
2.隱式調(diào)用??????this—>最近的調(diào)用者
3.顯示調(diào)用??????this—>指定的對(duì)象
4.構(gòu)造調(diào)用??????this—>構(gòu)造出的實(shí)例對(duì)象


作用域與執(zhí)行上下文的關(guān)系

對(duì)應(yīng)的執(zhí)行上下文 會(huì) 成為 作用域的屬性(執(zhí)行上下文最終會(huì)掛靠給作用域)
--作用域:
從瀏覽器的角度看作用域,它是一個(gè)c++對(duì)象,對(duì)象的屬性就是執(zhí)行上下文
從js語言的角度看作用域,它是一套規(guī)則(左查詢、右查詢)
--執(zhí)行上下文:
從瀏覽器的角度看執(zhí)行上下文,它是一個(gè)c++對(duì)象,對(duì)象的屬性就是它所管理的變量
從js語言的角度看執(zhí)行上下文,它是一套規(guī)則(規(guī)則如上)


提升

總結(jié):
1.提升會(huì)提升到當(dāng)前作用域的最頂層
2.變量提升是聲明的提升
3.函數(shù)提升是整體提升
4.函數(shù)的提升優(yōu)于變量的提升
注意點(diǎn):如果有兩個(gè)同名函數(shù),那么后面的函數(shù)會(huì)覆蓋前面所定義的函數(shù)(在js語言中沒有重載的概念,所以無法通過參數(shù)來判斷到底調(diào)用哪個(gè)函數(shù))。


編碼規(guī)范

1.使用變量前一定要先聲明(避免污染全局,迎合js引擎的提升規(guī)則)
2.在分支中最好不要定義函數(shù)(因?yàn)樵诜种е械暮瘮?shù)會(huì)變?yōu)楹瘮?shù)表達(dá)式)

注意點(diǎn):當(dāng)函數(shù)名與變量名重名時(shí)
function demo(){...}==>var demo = function(){...}
var demo   //跟函數(shù)名重復(fù),js引擎在解析代碼時(shí)會(huì)忽略此條聲明
demo=5;
demo()
//最終demo = function(){...}=5    5()    結(jié)果報(bào)錯(cuò)

隱式丟失

當(dāng)我們對(duì)函數(shù)進(jìn)行隱式調(diào)用(對(duì)象.屬性)時(shí),可能會(huì)發(fā)生隱式丟失的問題。

  1.以 對(duì)象.的形式 進(jìn)行變量的賦值時(shí)容易發(fā)生隱式丟失
            var fn = obj.test;
            fn()  // 發(fā)生了隱式丟失,原本this應(yīng)該指向obj,結(jié)果fn()獨(dú)立調(diào)用函數(shù),this指向全局

            var write = document.write;
            write("****") // 原本this應(yīng)該指向document,結(jié)果發(fā)生隱式丟失,所以報(bào)錯(cuò)

--

bind()函數(shù)

bind()函數(shù)(硬綁定)是用來解決隱式丟失問題的一種手段。
bind(this,[Arg1,Arg2...]),使用bind來實(shí)現(xiàn)硬綁定時(shí),會(huì)產(chǎn)生一個(gè)新的函數(shù),這個(gè)新的函數(shù)的this指向被綁定的對(duì)象(也就是bind中第一個(gè)參數(shù)this指定的對(duì)象),新的函數(shù)相當(dāng)于拷貝了一份原函數(shù),將bind中括號(hào)[]中的參數(shù)相當(dāng)于實(shí)參([]中的參數(shù)可以省略),傳給新函數(shù)中的形參。

<script>
        var module = {
            x: 42,     
            getX: function (a,b) {
                console.log(a,b);
                return this.x;
            }
        }

        var unboundGetX = module.getX;
        /*
        使用bind硬綁定產(chǎn)生一個(gè)boundGetX的函數(shù),boundGetX函數(shù)擁有跟原函數(shù)一樣的函數(shù)體(this指向了module),
        相當(dāng)于拷貝了一份原函數(shù),bind中[1,2]相當(dāng)于新函數(shù)的實(shí)參
        */
        var boundGetX = unboundGetX.bind(module,1,2);      
        console.log(boundGetX());
        console.log(boundGetX);
    </script>

函數(shù)調(diào)用優(yōu)先級(jí)

構(gòu)造函數(shù) > 顯示調(diào)用 > 隱式調(diào)用 > 普通調(diào)用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 來源:仗劍走天涯! 關(guān)于javascript的作用域的一些總結(jié),主要參考以上文章,加上自己的整理的理解。 近日對(duì)j...
    Michael_林閱讀 1,020評(píng)論 0 1
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,632評(píng)論 1 32
  • 今天是大年初一,凌晨五點(diǎn)半起床我們像往年一樣去隆興寺上香祈福,也不算多遠(yuǎn),九點(diǎn)就到家了,在這之前奶奶經(jīng)已...
    陶沐卉閱讀 837評(píng)論 0 7
  • 過度規(guī)劃是大多數(shù)空想主義者的愛好,這一部分人往往患有“過度規(guī)劃癥”,半夜和年底為病發(fā)高峰期。 就比...
    Close_朝生閱讀 513評(píng)論 0 1
  • 堅(jiān)持:不管現(xiàn)在的你處于怎樣的階段,是無助還是迷茫,堅(jiān)持都一定是最劃算的 。因?yàn)楫?dāng)你心生放棄時(shí),行為上就會(huì)得過且過,...
    子非魚lily閱讀 368評(píng)論 0 0

友情鏈接更多精彩內(nèi)容