【前端工程師手冊】JavaScript之作用域

什麼是作用域

來一段《你不知道的JavaScript-上卷》中的原話:

險些一切編程言語最基本的功用之一,就是能夠貯存變量當中的值,而且能在以後對這個 值舉行接見或修正,這些變量住在那裡?換句話說,它們貯存在那裡?最重要的是,順序須要時怎樣找到它們?這些題目申明須要一套設想優越的劃定規矩來存儲變量,而且以後能夠方便地找到這些變量。這套劃定規矩被稱為作用域

總之就是作用域就是一套劃定規矩,這個劃定規矩劃定了順序怎樣去找到變量

詞法作用域

先看一個例子:

function func1() {
    console.log(index)
}

function func2() {
    var index = 10
    func1()
}

var index = 100
func2()    // 100

為啥是100而不是10呢???
由於JavaScript是詞法作用域
詞法作用域簡樸地說就是:函數的作用域在聲明的時刻就決議好了。和詞法作用域相對的是動態作用域,動態作用域關注函數從那邊挪用
上面的代碼中,聲明func1時,它就處於全局作用域中,所以index就是100,縱然實行func1時也是。

函數作用域和塊作用域

前面講了JavaScript是詞法作用域,那末什麼時刻會建立作用域呢???
JavaScript重要是基於函數級別的作用域,也就是每個函數都邑建立一個作用域。為何說重要呢?由於with和try-catch語句也完成了塊作用域,固然了用的很少。

var flag = true;
if (flag) {
    var num = 10
}
console.log(num)    // 10

如果有塊級作用域的話,此時打印num應當報錯

function funcLevelScope() {
    var index = 10
}

console.log(index);    // ReferenceError

由於是函數級別的作用域,所以在函數表面接見不到函數內部的變量

怎樣模仿塊作用域

固然了,第一迴響反映就是在代碼錶面加上包裝函數不就行了,比方這模樣:

function scope() {
    var flag = true;
    if (flag) {
        var num = 10
    }
}
console.log(num)    // ReferenceError

然則此時的題目就是多了一個函數包裝,且我們能夠隨便的去運轉scope函數,這可能會形成不好的影響。
自實行函數處置懲罰了這個題目:

(function scope() {
    var flag = true;
    if (flag) {
        var num = 10
    }
})()
scope()    // ReferenceError
console.log(num)    // ReferenceError

包裝函數的聲明以 (function… 而不僅是以 function… 最先。只管看上去這並不 是一個很顯眼的細節,但實際上倒是非常重要的區分。函數會被看成函數表達式而不是一個規範的函數聲明來處置懲罰。

作用域內聲明提拔

變量聲明提拔
起首明白的是

var x = 10

像如許一句代碼能夠分為聲明和賦值兩句:

var x
x = 10

明白這個觀點再繼承進修

console.log(x)    // undefined
var x = 10

為何不直接報錯呢?
由於上面的代碼片斷即是:

var x    // 聲明提早
console.log(x)
x = 10

注意到變量的聲明提早到了當前作用域的最前面
函數聲明提拔

hoist()    // hoist!
function hoist() {
    console.log("hoist!")
}

為啥函數會勝利實行了,由於上面的代碼片斷相當於:

function hoist() {
    console.log("hoist!")
}
hoist()

函數聲明被提拔到了作用域的最前面
那末函數表達式會被提拔嗎??

hoist()    // TypeError
var hoist = function () {
    console.log("hoist")
}

由於這個相當於:

var hoist
hoist()    // TypeError
hoist = function () {
    console.log("hoist")
}

變量聲明提拔和函數聲明提拔的優先級
先說結論:函數會起首被提拔,然後才是變量
看例子:

console.log(x)
var x = 10
function x() {
    console.log('func x')
}

明顯此時打印的x是一個函數
這是由於上面的代碼片斷相當於:

function x() {
    console.log('func x')
}
var x
console.log(x)    // f x(){...}
x = 10

所以打印的是函數

參考資料:
JavaScript深切之詞法作用域和動態作用域
你不知道的JavaScript-上卷

    原文作者:亞古
    原文地址: https://segmentfault.com/a/1190000014801288
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞