2017-01-05 43 views
0

關於關鍵詞「讓我們在JavaScript

var funcs=[]; 
 
for(let i=0;i<3;i++){ 
 
\t funcs[i]=function(){ 
 
\t \t 
 
\t \t return i; 
 
\t } 
 
\t 
 
} 
 
alert(funcs[1]); 
 
alert(funcs[1]());
窗口警報2次。 第一個是這樣的:

function(){ 
 
\t \t return i; 
 
\t }

第二個這樣的

1 

但我卻不知道爲什麼funcs中[1]可以不執行報告錯誤'我不確定';

+0

如果您使用'var'而不是'let',它將始終返回'3' – zyMacro

回答

3

因爲在循環內創建的函數關閉了lexical environment它在創建時處於活動狀態。這個詞彙環境是(概念上)一個對象,它包含了定義在其中的局部變量(以及其他一些東西),包括變量i,在這種情況下是爲循環體的特定迭代而創建的變量(由於非常特殊的方式for在其初始化程序中處理let聲明)。這是JavaScript的核心技術之一「閉包」的概念。即使執行超出了範圍,一個給定的詞法環境與(一個函數返回,我們繼續下一個循環迭代等)相關聯,如果任何東西仍然有一個對該環境對象的引用,就像所有對象一樣繼續生活。

因爲如何for在其初始化處理let的,在funcs每個條目都有自己的詞彙環境,因而它的i自己的副本。

當您調用其中一個函數時,會創建一個新的環境對象,並將其「外部」環境設置爲附加到該函數的環境。當您在功能代碼中引用i時,它首先查看該功能的環境,如果在該處找不到i,它會在外部環境  —中查找它(在本例中)並在其中使用該環境。

在評論你說

如果使用 '變種' 而不是 '讓',它總是會返回 '3'

完全正確。使用var,i將被掛起到與for循環所在函數(或全局函數,如果這是全局代碼)相關的環境對象。因此,循環中創建的所有函數共享相同的i,當您給他們打電話時,它們的值爲3

這是let/constvar之間的本質區別之一:letconst有塊範圍,for具有用於在其初始值設定let特殊處理。

讓我們一起來看看這些不同的環境對象。假設此代碼:

funtion example() { 
    const funcs = []; 
    for (let i = 0; i < 3; ++i) { 
     funcs[i] = function() { 
      return i; 
     }; 
    } 
    funcs[1](); // 1 
} 
example(); 

當我們調用example,在const funcs = []之後,但在for循環開始之前,當前的環境對象是調用example創建的,所以我們必須在內存中是這樣的(忽略一些細節):

 
              +−−−−−−−−−−−−−−−−+ 
    current env>−−−−−−−−−−−−−−−−−−−−−−−−−>| `example` Call | 
              | Env Object | 
              +−−−−−−−−−−−−−−−−+ 
              | [[Outer]]  |>−−−>(The env obj for when `example` was created.) 
              | funcs   |>−+ 
              +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ 
                   +−>| (array) | 
                   +−−−−−−−−−−−+ 
                   | length: 0 | 
                   +−−−−−−−−−−−+ 

現在,for循環開始:創建一個新的每一次迭代環境對象到位「當前」之一,與前一個作爲其「外部」環境。一個i變量是在新的每一次迭代環境對象中創建,並給予價值0

 
       +−−−−−−−−−−−−−−+ 
    current env>−−>| Iteration 0 | 
       | Env Object | 
       +−−−−−−−−−−−−−−+   +−−−−−−−−−−−−−−−−+ 
       | [[Outer]] |>−−−−−−−>| `example` Call |             
       | i: 0   |   | Env Object |             
       +−−−−−−−−−−−−−−+   +−−−−−−−−−−−−−−−−+             
              | [[Outer]]  |>−−−>(The env obj for when `example` was created.) 
              | funcs   |>−+ 
              +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ 
                   +−>| (array) | 
                    +−−−−−−−−−−−+ 
                    | length: 0 | 
                    +−−−−−−−−−−−+ 

在循環迭代,我們創建了一個功能,並將其存儲在funcs。該函數獲取對當前環境對象的引用,它保留爲[[Environment]](這是一個實現性的東西,如果你看看這個函數,它不會在代碼級訪問,只是在JavaScript引擎中):

 
        +−−−−−−−−−−−−−−+ 
    current env>−+>| Iteration 0 | 
       / | Env Object |   +−−−−−−−−−−−−−−−−+ 
       / +−−−−−−−−−−−−−−+   | `example` Call | 
       + | [[Outer]] |>−−−−−−−>| Env Object | 
       | | i: 0   |   +−−−−−−−−−−−−−−−−+ 
       | +−−−−−−−−−−−−−−+   | [[Outer]]  |>−−−>(The env obj for when `example` was created.) 
       |        | funcs   |>−+ 
       |        +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ 
       |             +−>| (array) | 
       |             +−−−−−−−−−−−+ 
       |             | length: 1 |  +−−−−−−−−−−−−−−−−−+ 
       |             | 0   |>−−−−−>| Function 0 | 
       |             +−−−−−−−−−−−+  +−−−−−−−−−−−−−−−−−+ 
       |                  | [[Environment]] |>−−−−−+ 
       |                  +−−−−−−−−−−−−−−−−−+  | 
       |                         | 
       +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ 

現在,這是的letfor初始化巧妙的處理工作(事實上,巧妙處理的letconst一個for循環體內部以及):一個環境對象下一個迭代被創建,並且i的值是複製i爲先前的迭代到i爲下一次迭代。因此,我們有:

 
        +−−−−−−−−−−−−−−+ 
+−−−−−−−−−−−−−−−−−>| Iteration 0 | 
|     | Env Object |   +−−−−−−−−−−−−−−−−+ 
|     +−−−−−−−−−−−−−−+   | `example` Call | 
|     | [[Outer]] |>−−−+−−−>| Env Object | 
|     | i: 0   | /  +−−−−−−−−−−−−−−−−+ 
|     +−−−−−−−−−−−−−−+ +  | [[Outer]]  |>−−−>(The env obj for when `example` was created.) 
|         |  | funcs   |>−−−+ 
|         |  +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ 
|         |       +−−>| (array) | 
|     +−−−−−−−−−−−−−−+ |        +−−−−−−−−−−−+ 
| current env>−+>| Iteration 1 | |        | length: 1 |  +−−−−−−−−−−−−−−−−−+ 
|     | Env Object | |        | 0   |>−−−>| Function 0 | 
|     +−−−−−−−−−−−−−−+ |        +−−−−−−−−−−−+  +−−−−−−−−−−−−−−−−−+ 
|     | [[Outer]] |>−+             | [[Environment]] |>−+ 
|     | i: 0   |              +−−−−−−−−−−−−−−−−−+ | 
|     +−−−−−−−−−−−−−−+                   | 
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ 

然後在新的環境中i遞增爲1,並且創建並存儲在funcs一個新的功能,給我們:

 
        +−−−−−−−−−−−−−−+ 
+−−−−−−−−−−−−−−−−−>| Iteration 0 | 
|     | Env Object |   +−−−−−−−−−−−−−−−−+ 
|     +−−−−−−−−−−−−−−+   | `example` Call | 
|     | [[Outer]] |>−−−+−−−>| Env Object | 
|     | i: 0   | / +−−−−−−−−−−−−−−−−+ 
|     +−−−−−−−−−−−−−−+ +  | [[Outer]]  |>−−−>(The env obj for when `example` was created.) 
|         |  | funcs   |>−−−+ 
|         |  +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ 
|         |       +−−>| (array) | 
|     +−−−−−−−−−−−−−−+ |        +−−−−−−−−−−−+ 
| current env>−+>| Iteration 1 | |        | length: 2 |  +−−−−−−−−−−−−−−−−−+ 
|    / | Env Object | |        | 0   |>−−−>| Function 0 | 
|    / +−−−−−−−−−−−−−−+ |        | 1   |>−+ +−−−−−−−−−−−−−−−−−+ 
|    + | [[Outer]] |>−+        +−−−−−−−−−−−+ | | [[Environment]] |>−−−+ 
|    | | i: 1   |             | +−−−−−−−−−−−−−−−−−+ | 
|    | +−−−−−−−−−−−−−−+             |       | 
|    |                  | +−−−−−−−−−−−−−−−−−+ | 
|    |                  +−>| Function 1 | | 
|    |                   +−−−−−−−−−−−−−−−−−+ | 
|    |                   | [[Environment]] |>−+ | 
|    |                   +−−−−−−−−−−−−−−−−−+ | | 
|    |                        | | 
|    +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | 
|                            | 
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ 

然後在那結束迭代,我們最後一次迭代再做這件事,並獲得:

 
        +−−−−−−−−−−−−−−+ 
+−−−−−−−−−−−−−−−−−>| Iteration 0 | 
|     | Env Object |   +−−−−−−−−−−−−−−−−+ 
|     +−−−−−−−−−−−−−−+   | `example` Call | 
|     | [[Outer]] |>−−+−−+ −>| Env Object | 
|     | i: 0   |// +−−−−−−−−−−−−−−−−+ 
|     +−−−−−−−−−−−−−−+ | | | [[Outer]]  |>−−−>(The env obj for when `example` was created.) 
|         | | | funcs   |>−−−+ 
|         | | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ 
|         | |       +−−>| (array) | 
|     +−−−−−−−−−−−−−−+ | |        +−−−−−−−−−−−+ 
| +−−−−−−−−−−−−−−−>| Iteration 1 | | |        | length: 3 |  +−−−−−−−−−−−−−−−−−+ 
| |    | Env Object | | |        | 0   |>−−−−−>| Function 0 | 
| |    +−−−−−−−−−−−−−−+ | |        | 1   |>−−−+ +−−−−−−−−−−−−−−−−−+ 
| |    | [[Outer]] |>−+ |        | 2   |>−+ | | [[Environment]] |>−−−−−+ 
| |    | i: 1   | |        +−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−+  | 
| |    +−−−−−−−−−−−−−−+ |            | |       | 
| |         |            | | +−−−−−−−−−−−−−−−−−+  | 
| |    +−−−−−−−−−−−−−−+ |            | +−>| Function 1 |  | 
| | current env>−+>| Iteration 2 | |            | +−−−−−−−−−−−−−−−−−+  | 
| |    / | Env Object | |            | | [[Environment]] |>−−−+ | 
| |   + +−−−−−−−−−−−−−−+ |            | +−−−−−−−−−−−−−−−−−+ | | 
| |   | | [[Outer]] |>−−−+            |       | | 
| |   | | i: 2   |             | +−−−−−−−−−−−−−−−−−+ | | 
| |   | +−−−−−−−−−−−−−−+             +−−−>| Function 2 | | | 
| |   |                   +−−−−−−−−−−−−−−−−−+ | | 
| |   |                   | [[Environment]] |>−+ | | 
| |   |                   +−−−−−−−−−−−−−−−−−+ | | | 
| |   |                        | | | 
| |   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | 
| |                            | | 
| +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | 
|                             | 
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ 

當我們調用funcs[1](),創建該呼叫的環境並將其[[Outer]]環境設置爲該函數的[[Environment]]。因此,只要我們在功能return i之前,我們(留下了一些細節):

 
       +−−−−−−−−−−−−−−+ 
current env>−−>| Call to  | 
       | `funcs[1]()` | 
       | Env Object | 
       +−−−−−−−−−−−−−−+ 
       | [[Outer]] |>−−+ 
       +−−−−−−−−−−−−−−+ | 
            |  
            |  +−−−−−−−−−−−−−−−−+ 
      +−−−−−−−−−−−−−−−−−−−−+  | `example` call | 
      |      +−−−>| Env Object  | 
      |      | +−−−−−−−−−−−−−−−−+ 
      |      | | [[Outer]]  |>−−−>(The env obj for when `example` was created.) 
      |      | | funcs   |>−+ 
      |      | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ 
      |      |      +−>| (array) | 
      \  +−−−−−−−−−−−−−−+ |       +−−−−−−−−−−−+ 
    +−−−−−−−−−−−+−−−>| Iteraton 1 | |       | length: 3 |  +−−−−−−−−−−−−−−−−−+ 
    |    | Env Object | |       | 0   |>−−−−−>| (function) | 
    |    +−−−−−−−−−−−−−−+ |       | 1   |>−−−+ +−−−−−−−−−−−−−−−−−+ 
    |    | [[Outer]] |>−+       | 2   |>−+ | | [[Environment]] |>... 
    |    | i: 1   |        +−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−+ 
    |    +−−−−−−−−−−−−−−+            | |      
    |                    | | +−−−−−−−−−−−−−−−−−+ 
    |                    | +−>| (function) | 
    |                    | +−−−−−−−−−−−−−−−−−+ 
    |                    | | [[Environment]] |>−−−−+ 
    |                    | +−−−−−−−−−−−−−−−−−+  | 
    |                    |       | 
    |                    | +−−−−−−−−−−−−−−−−−+  | 
    |                    +−−−>| (function) |  | 
    |                     +−−−−−−−−−−−−−−−−−+  | 
    |                     | [[Environment]] |>... | 
    |                     +−−−−−−−−−−−−−−−−−+  | 
    |                           | 
    |                           | 
    +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ 

當函數查找i,它看起來在當前的環境對象。由於它不在那裏,它看起來是[[Outer]]對象。它在那裏找到它,值爲1,所以這就是它使用的價值。

相反,如果我們使用vari被提升到呼叫的環境對象example(其中funcs是),所以在循環之後,我們有這個代替(注意i不再在每個迭代環境):

 
        +−−−−−−−−−−−−−−+ 
+−−−−−−−−−−−−−−−−−>| Iteration 0 | 
|     | Env Object |   +−−−−−−−−−−−−−−−−+ 
|     +−−−−−−−−−−−−−−+   | `example` Call | 
|     | [[Outer]] |>−−+−−+−>| Env Object | 
|     +−−−−−−−−−−−−−−+// +−−−−−−−−−−−−−−−−+ 
|         | | | [[Outer]]  |>−−−>(The env obj for when `example` was created.) 
|         | | | i: 3   | 
|         | | | funcs   |>−−−+ 
|         | | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ 
|         | |       +−−>| (array) | 
|     +−−−−−−−−−−−−−−+ | |        +−−−−−−−−−−−+ 
| +−−−−−−−−−−−−−−−>| Iteration 1 | | |        | length: 3 |  +−−−−−−−−−−−−−−−−−+ 
| |    | Env Object | | |        | 0   |>−−−−−>| Function 0 | 
| |    +−−−−−−−−−−−−−−+ | |        | 1   |>−−−+ +−−−−−−−−−−−−−−−−−+ 
| |    | [[Outer]] |>−+ |        | 2   |>−+ | | [[Environment]] |>−−−−−+ 
| |    +−−−−−−−−−−−−−−+ |        +−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−+  | 
| |         |            | |       | 
| |         |            | | +−−−−−−−−−−−−−−−−−+  | 
| |    +−−−−−−−−−−−−−−+ |            | +−>| Function 1 |  | 
| | current env>−+>| Iteration 2 | |            | +−−−−−−−−−−−−−−−−−+  | 
| |   /| Env Object | |            | | [[Environment]] |>−−−+ | 
| |   + +−−−−−−−−−−−−−−+ |            | +−−−−−−−−−−−−−−−−−+ | | 
| |   | | [[Outer]] |>−−−+            |       | | 
| |   | +−−−−−−−−−−−−−−+             | +−−−−−−−−−−−−−−−−−+ | | 
| |   |                  +−−−>| Function 2 | | | 
| |   |                   +−−−−−−−−−−−−−−−−−+ | | 
| |   |                   | [[Environment]] |>−+ | | 
| |   |                   +−−−−−−−−−−−−−−−−−+ | | | 
| |   |                        | | | 
| |   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | 
| |                            | | 
| +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | 
|                             | 
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ 

這意味着當我們調用funcs[1](),爲它創建一個新的環境,其[[Outer]]設置爲功能的[[Environment]],只是return i之前,我們有:

 
       +−−−−−−−−−−−−−−+ 
current env>−−>| Call to  | 
       | `funcs[1]()` | 
       | Env Object | 
       +−−−−−−−−−−−−−−+ 
       | [[Outer]] |>−−+ 
       +−−−−−−−−−−−−−−+ | 
            |  
            |  
      +−−−−−−−−−−−−−−−−−−−−+  +−−−−−−−−−−−−−−−−+ 
      |       | `example` call | 
      |      +−−−>| Env Object  | 
      |      | +−−−−−−−−−−−−−−−−+ 
      |      | | [[Outer]]  |>−−−>(The env obj for when `example` was created.) 
      |      | | i: 3   | 
      |      | | funcs   |>−+ 
      |      | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ 
      |      |      +−>| (array) | 
      \  +−−−−−−−−−−−−−−+ |       +−−−−−−−−−−−+ 
    +−−−−−−−−−−−+−−−>| Iteration 1 | |       | length: 3 |  +−−−−−−−−−−−−−−−−−+ 
    |    | Env Object | |       | 0   |>−−−−−>| (function) | 
    |    +−−−−−−−−−−−−−−+>−+       | 1   |>−−−+ +−−−−−−−−−−−−−−−−−+ 
    |    | [[Outer]] |        | 2   |>−+ | | [[Environment]] |>... 
    |    +−−−−−−−−−−−−−−+        +−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−+ 
    |                    | |      
    |                    | | +−−−−−−−−−−−−−−−−−+ 
    |                    | +−>| (function) | 
    |                    | +−−−−−−−−−−−−−−−−−+ 
    |                    | | [[Environment]] |>−−−−+ 
    |                    | +−−−−−−−−−−−−−−−−−+  | 
    |                    |       | 
    |                    | +−−−−−−−−−−−−−−−−−+  | 
    |                    +−−−>| (function) |  | 
    |                     +−−−−−−−−−−−−−−−−−+  | 
    |                     | [[Environment]] |>... | 
    |                     +−−−−−−−−−−−−−−−−−+  | 
    |                           | 
    |                           | 
    +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ 

所以當函數查找i,它沒有找到它在當前的環境下,它不會在第一[[Outer]]環境找到它,但它確實找到它在[[Outer]]環境,價值3,所以這是它使用的價值。

+0

謝謝。但是我仍然有一些問題。這是什麼意思,「我沒有連接到爲循環迭代創建的執行上下文,它連接到包含for循環的執行上下文」?什麼時候它發生了'所以funcs中的每個條目都得到了它自己的'我'的副本? – zyMacro

+0

@zyMacro:我已經更新了一些圖表來幫助。 –

+0

非常感謝。但是在中國深夜。明天早上我會清楚地看到它。不能等待它。 – zyMacro