2017-01-05 28 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