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

Но я не konw почему funcs [1] может казнили не сообщает об ошибке 'i undefined';

+0

Если вы используете 'var' not 'let', он всегда будет возвращать '3' – zyMacro

ответ

3

Поскольку функция, созданная в цикле , закрывает более , который активен, когда он был создан. Эта лексическая среда является (концептуально) объектом, который содержит локали, определенные внутри него (и некоторые другие вещи), включая переменную i, в этом случае созданную для этой конкретной итерации тела цикла (из-за особого способа for обрабатывает декларации let в своем инициализаторе). Это концепция «закрытия», одной из центральных технологий JavaScript. Даже когда выполнение выходит за пределы области, с которой связана данная лексическая среда (функция возвращает, мы переходим к следующей итерации цикла и т. Д.), Если что-то еще имеет ссылку на этот объект среды, как и все объекты, Живет на.

Из-за того, как for ручки let в инициализаторе, каждая запись в funcs получает свою собственную лексическую среду, и, таким образом, свою собственную копию i.

Когда вы вызываете одну из этих функций, создается новый объект среды со своей «внешней» средой, установленной в среду, присоединенную к этой функции. Когда вы ссылаетесь на код i внутри функционального кода, он сначала смотрит в среду функции, и если i не найден там, он ищет внешнюю среду   —, где он находит ее (в данном случае) и использует ее.

В комментарии вы сказали

Если вы используете 'вар' не "давайте, он всегда будет возвращать '3'

Совершенно верно. С var, i будет вставлен в объект окружения, связанный с функцией цикла for (или глобальный, если это глобальный код). Таким образом, все функции, созданные в цикле, имеют те же самые i, которые к тому моменту, когда вы их вызываете, имеют значение 3.

Это одна из существенных различий между let/const и var: let и const имеют блок сферу, и 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]] |>−−−−−+ 
       |                  +−−−−−−−−−−−−−−−−−+  | 
       |                         | 
       +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ 

Теперь это где умное обращение let в for инициализаторах работает (и на самом деле, умные обработки из let и const внутри тела for передачи контура, как хорошо): A нового объекта среды для следующий итерация создается, а значение 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](), в ENVIRO для его вызова создается, а его среда [[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

Спасибо. Но у меня все еще есть некоторые вопросы. Что это значит: «i не связан с контекстом выполнения, созданным для итерации цикла, он связан с контекстом выполнения, содержащим ваш цикл for»? И когда это произошло? Итак, каждая запись в funcs получает свою собственную копию i? – zyMacro

+0

@zyMacro: Я обновил некоторые диаграммы, чтобы помочь. –

+0

Большое вам спасибо. Но поздно ночью в Китае. Я буду читать это ясно завтра утром. Не могу дождаться этого. – zyMacro

 Смежные вопросы

  • Нет связанных вопросов^_^