js中,函數的閉包、做用域跟[[Scopes]]的關係

[[Scopes]]是函數的內部屬性,是沒法訪問的,可是咱們能夠經過Chrome的開發者工具看到它的樣子。數組

d

  1. 咱們如今聲明個函數foo
  2. 須要查看foo的原型對象才能看到[[scopes]]屬性,由於foo.prototype.constructorfoo指向同一個函數,因此點開constructor選項。
  3. 如今咱們終於看到了[[Scopes]]屬性。

能夠清楚的看到它是一個 數組,只有一個元素 Global也就是全局對象,通過我目測這個 Global應該和 window對象是同一個對象。

// 定義一個全局的變量
var a = 'global property'

function foo () {
    console.log(a)
}

foo() // 此時會輸出global property
複製代碼

如上代碼所示,此時咱們再看foo[[Scopes]]屬性bash

會發現 Global對象裏增長了一個 a屬性,這和 window對象表現一致。事實上在函數 foo裏面執行 console.log(a)的時候,變量 a就是從這個 Global對象內讀取的。

function outer () {
    var a = 'property of outer scope'
    
    return function inner () {
        console.log(a)
    }
}

var inner = outer() 
inner() // 如你們所料,會輸出property of outer scope
複製代碼

此時咱們再看一下inner[[Scopes]]屬性閉包

會發現 [[Scopes]]數組的前面新添加了一個叫 Closure的對象,從字面上看這不就是 閉包的意思嗎,咱們展開看一下

果真有咱們 閉包裏的屬性 a,其實 inner函數裏的 console.log(a)中的 a就是從設個 Closure對象裏面讀取的。咱們再來看一個例子

function outer () {
    var a = 1
    
    function inner () {
        var b = 2
        
        return function innermost () {
            console.log(a, b)
        }
    }
    
    return inner()
}

var innermost = outer()
innermost() // 此時輸出的值是1 2
複製代碼

看一下innermost[[Scopes]]屬性,以下圖函數

會發如今 Scopes數組的開頭又增長了一個閉包,是按照從內到外的順序排列的,讓咱們點開看一下

果真,這裏的兩個 閉包對象分別包含了 innermost須要訪問的全部變量。這就是做用域鏈的概念,當一個函數被調用的時候,函數內部訪問的對象會先從函數本身的做用域內部進行查找,若是沒找到對應的變量,就會從 [[Scopes]]數組的第一項 閉包對象進行查找,若是還沒找到就繼續到下一個 閉包對象查找,以此類推。

完。

相關文章
相關標籤/搜索