攻克-✪-JavaScript作用域

1 定義:

作用域日常有很多叫法比如

  • this綁定的值
  • this綁定值定義的執行上下文
  • 一個變量的“生命週期”、
  • 變量的值解析方案或詞法綁定

作用域通俗的講就是一個變量多長時間內保持一定的值。

2 分類:

作用域從範圍上劃分可以分成全局作用域局部作用域(常見的是函數內部,也叫函數作用域)。

作用域按照工作模式分詞法作用域(靜態作用域)動態作用域。

2.1 全局作用域

1.在全局聲明的變量生命週期將跨越整個程序(盡力少些,並且不好維護)。

2.在JS中沒有用var 關鍵字聲明的變量都是全局變量,能被程序中任何函數或方法訪問。

    aVariable = '我是全局變量'

    function aTest() {
        console.log(aVariable)
    }
    aTest() // 我是全局變量

就是因爲任何一段代碼可以隨便改變它們,會引起之後一些的麻煩,相當的危險。

2.2 詞法作用域

先說說詞法,詞法的中文意思是特定文本內語詞的構成和使用的法則。

在大部分編譯器也有這類似步驟,對源代碼進行字符檢查,如果是有狀態的解析過程,就會賦予單詞語義。

詞法作用域是指一個變量的可見性,及其文本表述的模擬值。(大概先記着有個印象)

上個代碼:

    aVar = 'One'

    function aFun() {
        let aVar = 'Two'
        return [1, 2, 3].map(function (item) {
            var aVar = 'three'
            console.log([aVar, item].join(''))
        })
    }
    aFun() //three1  three2   three3

分析

換句話說,詞法作用域是由你寫代碼時將變量或塊作用域寫在哪裏所決定的。

2.3 動態作用域

在編程中最容易被低估或過度濫用的概念就是動態作用域。

aVariable = '我是全局變量'
    function aTest() {
        var aVariable = "我是TEST作用域的變量"

        function childFun() {
            var childVar = "我是child的變量"
            console.log(aVariable, childVar)
        }
        childFun()
    }
    aTest() // 我是TEST作用域的變量 我是child的變量

 

 

 

 

但是如果在當前作用域中沒有查到值,就會向上級作用域去查,直到查到第一個值,最如果一直沒有會一層層直到查到全局作用域,這麼一個查找過程形成的鏈條就叫做作用域鏈

 

 aVariable = '我是全局變量'

    function aTest() {
        var aVariable = "我是TEST作用域的變量"
        childFun()
    }

    function childFun() {
        var childVar = "我是child的變量"
        console.log(aVariable, childVar)
    }
    aTest() // 我是全局變量 我是child的變量

 

動態作用域的核心是維護一個命名綁定棧的全局映射。

缺點:任何給定的綁定的值,在確定調用其函數之前,都是不可知的

(JS中this引用是動態作用域,尤其是事件處理函數中,如果點擊按鈕得到的this沒用,會破壞程序的正常運行,是危險的)

 

2.4 函數作用域

 

在任意代碼片段外部添加包裝函數,可以將內部的變量和函數定義“隱藏”起來,外部作用域無法訪問包裝函數內部的任何內容。

function testFun(n) {
    for(var i=0;i<n;i++);
    console.log(i)
}
testFun(100) // 100

搜索在JS中所有在函數體內的var聲明都會隱式地移到函數的頂部,JS重新排列變量聲明的動作成爲吊裝(hoisting)

上面的代碼實際重新排列就成這樣了

    function testFun(n) {
        var i;
        for (i = 0; i < n; i++);
        console.log(i)
    }
    testFun(100) // 100

舉個例子:

    i = 100
    function testFun(n) {
        console.log(i)
        var i = 111;
    }
    testFun()
    console.log(i)

原因分析:

    i = 100 // 定義全局的 i

    function testFun(n) {
        var i; // JS吊裝排列
        console.log(i) // 此時還沒有定義說undefined
        i = 111; // 定義當前作用域的 i
    }
    testFun()
    
    console.log(i) // 打印全局變量i

 

【ES6的let填坑了,會直接報錯 Uncaught ReferenceError: Cannot access 'i' before initialization(初始化之前不能訪問')

Hositing的概念真的理解了麼,再來個測試~~~ do it~

 

    i = 100 

    function testFun(n) {
        console.log(i) 
        i = 111; 
    }
    testFun()

    console.log(i) 

 

 

 

 

 

 

 

 

 

發佈了39 篇原創文章 · 獲贊 24 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章