從運行時聊javascript做用域

什麼是做用域

做用域是指程序源代碼中定義變量的區域。它規定了程序執行時對該變量的訪問權限。javascript

js中的做用域有什麼特色

前面咱們聊了什麼是做用域,那javascript中做用域都有哪些特色呢?接下來咱們就聊聊這個java

動態做用域和靜態做用域

在討論這個問題以前先看一段以下代碼:bash

var a = 1
function f1 () {
    console.log(a)
}
function f2 () {
    var a = 2
    f1()
}
f2()
複製代碼

上述代碼會打印1。這就很好的說明了,在javascript中,其做用域是靜態做用域也就是詞法做用域。通俗點來說,函數的做用域在定義的時候就已經定了。套用做用域的概念就是函數f1在定義的時候,就規定了訪問的變量a是全局變量中的a,所以當在函數f2中執行的時候,函數f1沒有訪問函數f2中的局部變量a的權限。函數

全局做用域、局部做用域及塊做用域

  • 全局做用域:變量在全局聲明就擁有了全局做用域
  • 局部做用域:在函數內聲明的變量,至於在函數體內有定義,他們是局部變量,做用域是局部性的,所以其權限就是局部做用域。特別注意:函數參數也是局部變量
  • 塊級做用域:在一些類c語言中,花括號內的每一段代碼都具備各自的做用域,變量在聲明他們的代碼塊外是不可見的,咱們稱之爲塊級做用域。在ECMAScript6以前,javascript中是沒有塊級做用域的概念的。
    這幾個做用域從優先級上來講,塊級做用域 > 函數做用域 > 全局做用域 咱們來看下面一段代碼:
var scope = 'global'
function checkscope () {
    var scope = 'local'
    let i = 10
    {
        let i = 8
        console.log(i) // => 8
    }
    return scope
}
checkscope() // => 'local'
複製代碼

變量提高

在以下代碼中咱們定義了變量a,b,c,他們都在同一個做用域內。ui

function test (d) {
    console.log(a) // => undefined
    console.log(b) // => undefined
    console.log(c) // => undefined
    var a = 1
    if (d > 0) {
        var b = 2
        for (var c = 0; c < 10; c ++) {
            console.log(c) // =>0 - 9
        }
        console.log(c) // =>10
    }
    console.log(b) // =>2
}
test(1)
複製代碼

咱們發現javascript函數做用域在整個函數體內始終可見,即使是在判斷語句和循環語句中也沒有收到影響。這意味着變量在聲明前就已經可用。javascript的這個特性就稱爲聲明提早也叫變量提高。spa

做用域鏈

到底全局做用域跟局部做用域什麼關係呢?還有你們可能會疑惑,咱們再聊javascript靜態做用域的時候函數f1是怎樣訪問到全局變量a的呢?code

  • 做用域鏈 每一段javascript代碼(全局或者函數)都有一個與之關聯的做用域鏈,這個做用域鏈是一個對象列表或者鏈表,這組對象定義了這段代碼"做用域中"的變量。當javascript須要查找變量a的時候,他會沿着這條鏈查找第一個對象看它有沒有a變量,若是沒有就查找第二個對象,若是尚未就接着查找下一個,一次類推,直到找到,若做用域鏈上沒有一個對象含有a屬性,那麼就認爲這段做用域鏈上不存在該屬性,最終或拋出一個引用異常錯誤。
  • 在javascript的最頂層代碼中(不包含任何函數定義的代碼),做用域鏈由一個全局對象組成。在不包含嵌套的函數體中,做用域鏈上有兩個對象,第一個是定義函數參數和函數對象的對象,第二個就是全局對象。

今天咱們聊了一聊javascript中的做用域,可能你們已經發現啦我說了半天做用域好像跟javascript運行時沒有什麼關係啊,彆着急,後續還會在接着聊。對象

相關文章
相關標籤/搜索