本文做者是Peter Rybin,Chrome開發者工具團隊成員. javascript
本文中,咱們將經過使用Chrome的開發者工具,來學習JavaScript中的兩個重要概念」閉包」和」內部屬性」. java
首先要講的是閉包(closure) - JavaScript中最有名的東西之一.一個閉包就是一個使用了外部變量的函數.查看下面的例子: git
1 2 3 4 5 6 7 8 9 |
function A(a, b, c){var ar =[a, b, c];returnfunction B(i){return ar[i];};} var b = A('Here','I','am'); console.log( b(1)); |
函數聲明以後的第一條語句調用了函數A,函數A建立了一個值爲數組[a,b,c]的局部變量ar,返回了一個函數B(存儲在了變量b中),而後運行結束. github
第二條語句調用了函數B(b),返回並打印出了數組ar.這就意味着A中的數組ar在A結束執行後仍然存在.可是它存儲在什麼地方呢?固然,在b上!可是到底是存在b的哪裏呢?某個屬性中?不是的. chrome
這是JavaScript語言的一個核心特性:一個函數能夠持有外層做用域的變量,而且除了調用該函數之外沒有任何其餘方法能夠訪問到這些變量. 數組
從如今開始,chrome的開發者工具可讓閉包中的外部變量現形.在監控表達式(Watch Expressions)面板中查看函數實例b,展開它的屬性後,應該會有一個稱爲<function scope>的子節點.全部被綁定的閉包變量都能在這裏看到,這些變量就是在函數調用時可能會被用到的變量. 閉包
開發者工具還能顯示出另一個東西,叫作內部屬性(internal property). 函數
假設你的代碼中有個變量s,並且還執行了下面這樣的操做: 工具
1 |
s.substring(1,4)// 返回'ell' |
你以爲s確定是個字符串值嗎? 這可不必定.它也有多是個字符串包裝對象.嘗試下面的監控表達式: 學習
1 2 |
"hello" Object("hello") |
第一個表達式是一個普通的字符串字面量,第二個是一個功能完整(full-featured)的對象.使人費解的是,這兩個值幾乎有徹底相同的表現.可是第二個表達式才真正的擁有本身的屬性,而且你也能夠在它身上添加自定義的屬性.展開它的全部屬性你會看到,它不是一個徹底常規的對象:它有一個內部屬性[[PrimitiveValue]] ,被包裝的字符串值就存儲在這個屬性裏面.你不能在JavaScript代碼中訪問到這個內部屬性,可是你能在開發者工具的中看到它.
還有哪些值擁有內部屬性?那就是綁定函數(bound function).綁定函數也算是一種包裝對象,只不過被包裝的是個函數.嘗試執行下面的兩條語句:
1 2 |
function Sum(a, b){return a + b;}var inc = Sum.bind(null,1);// 將形參a綁定爲1,this綁定爲null |
若是你把Sum和inc放在監控表達式面板中對比一下,你會看到,它們都是函數,但inc是一個不透明(non-transparent )的函數:你看不到它的函數體內容,也不能看到它定義時的做用域.
這就是綁定函數的工做原理.在開發者工具中,你會看到[[TargetFunction]], [[BoundArgs]]以及[[BoundThis]]這三個內部屬性.它們都代表了inc是一個綁定函數,以及一些更具體的信息:inc綁定的目標函數是Sum,綁定了一個參數1,綁定的this值是null.