2013-12-21 16 views
2

Как сказано в sec 10.4.3Переменные/лексические среды

Следующие шаги выполняются, когда управление переходит в выполнения контекст для кода функции, содержащейся в объекте функции F, вызывающей при условии thisArg и вызывающего абонента при условии argumentsList:

  1. Если код функции является строгим кодом, установите значение ThisBinding для этогоArg.
  2. Иначе, если thisArg имеет значение null или undefined, установите значение ThisBinding для глобального объекта.
  3. Else, если Type (thisArg) не является объектом, установите значение ThisBinding для ToObject (thisArg).
  4. Else set ThisBinding to thisArg.
  5. Пусть localEnv является результатом вызова NewDeclarativeEnvironment, передающего значение внутреннего свойства [[Область]] F в качестве аргумента .
  6. Установите LexicalEnvironment на localEnv.
  7. Задайте переменную окружения localEnv.
  8. Пусть код является значением внутреннего свойства F [[Code]].
  9. Выполнение обязательного связывания с использованием кодового кода функции и argumentsList, как описано в 10.5.

Рассмотрим следующий фрагмент кода:

function foo(){ 
    var a={p:'p'}; 
    o={c:'c'}; 
} 

Таким образом, мы имеем следующее:

  1. код нашей функции разве строгий код
  2. thisArg является нулевым, следовательно, ThisBinding для глобального объекта
  3. ---
  4. ---
  5. Я не понимаю, какие связки будут содержать environment record, представленные [[Scope]] внутренняя недвижимость.
  6. Установите LexicalEnvironment к окружающей среде, которая geted на шаге 5.
  7. Установите VariableEnvironment в среде, которая geted на шаге 5.
  8. Выполните связывание instatiation декларации.

На шаге 8 привязки создаются в среде VariableEnvironment, но не в LexicalEnvironment. Но в sec 10.3 сказал, что

Когда контекст выполнения создается его LexicalEnvironment и компоненты VariableEnvironment изначально имеют одинаковое значение.

Вопрос:

Почему сразу после создания контекста выполнения LexicalEnvironment и VariableEnvironment по-прежнему равно в моем случае выше?

+0

Я не уверен, понял ли я этот вопрос. «LexicalEnvironment» и «VariableEnvironment» получают одинаковое значение, назначенное в 6 и 7. –

+0

@Felix Kling На шаге 8 переменные контекста и функции, объявленные в коде, будут добавлены как привязки в записи среды VariableEnvironment. Но как насчет LexicalEnvironment? Будут ли эти привязки добавлены в LexicalEnvironment на шаге 8? А что такое '[[Scope]]' внутреннее свойство функции в моем конкретном случае? –

+0

Это хороший вопрос. Я бы предположил, что это похоже на объекты: LexicalEnvironment и VariableEnvironment относятся к одной и той же среде, и, следовательно, любые изменения, внесенные в эту среду, видны через оба компонента. В вашем примере '[[Scope]]' будет ссылаться на лексическую среду глобального контекста выполнения, поскольку вы определили функцию в глобальной области. См. Http://www.ecma-international.org/ecma-262/5.1/#sec-13 –

ответ

2

Я не уверен, я понимаю ваш вопрос, но это, как я понимаю, сек 10.4.3:

шаги с 1 по 4 имеют дело со значением этого. В основном, в строгом режиме, будет оставлен до значения null или undefined, а не по умолчанию для глобального объекта (window в случае браузера). Это охватывает случаи, когда функция не вызывается через обычные механизмы обработчика объекта или события.

шаг 5 до 7 означает, что новая среда именование создается каждый раз при входе в функцию. В нем описывается создание этой среды, которая связана с предыдущей, чтобы сформировать текущую область имен.

Для каждой новой функции две среды сосуществуют. Когда имя разрешено, сначала выполняется поиск по лексической среде, а затем переменная среда. Если оба запроса не выполняются, процесс повторяется на верхнем уровне цепочки окружения, пока не будет обнаружена глобальная область «catch-all». В этой области все идентификаторы обрабатываются как свойства глобального объекта (window). Вы можете представить его как полный код, заключенный в блок with (window).

Лексическую среду можно рассматривать как временное увеличение области переменных. Лексические и переменные среды: functionnally идентичны до тех пор, пока вы не измените лексическую среду с помощью двух конкретных операторов: with или catch. Это не значит, что они реализованы как идентичные структуры данных.

С точки зрения реализации вы можете представить себе лексическую среду как пустой список и переменную среду как список, содержащий все локальные переменные и имена параметров. Когда встречается оператор catch или with, лексический список заполняется новыми именами, которые будут иметь приоритет над хранимыми в списке переменных.

catch просто сделает свой аргумент доступным для разрешения имен (т. Е. Позволит вам ссылаться на параметр исключения). Не имеет большого значения, поскольку новое имя так же явно, как и параметр функции.

with - более опасное зверь. Он создаст новую среду с именами всех свойств объекта, переданного в качестве аргумента. Объем будет состоять из цепочки переменная среды плюс этот новый лексический окружающая среда. Здесь новые имена, доступные для разрешения, «скрыты» внутри объекта. Например:

var a = 'a', b = 'surprise!', o = {a:'a'}; 
with (o) { a = b; } 
console.log (a+" "+b+" "+o.a); 

даст

a surprise! surprise! 

a решается, как o.a, поскольку o содержит свойство с именем a. b не найден внутри лексических окружающей среды и, таким образом, текущий переменная окружающая среда суждена и переменная 'b' не найден. Это довольно опасный механизм, потому что, если вы считаете, что объект содержит заданное свойство, а на самом деле его нет, вы вместо этого ссылаетесь на переменную за пределами текущей области. Например, простая опечатка, как это:

with (element.style) {leftt = '10px';} 

установит window.leftt свойство '10px', если не случится объявили переменную с именем leftt где-то в текущей области.

Теперь, если вы дадите глупые имена, такие как «i» или «j», к вашим свойствам объекта, скорее всего, вы будете клонировать индекс случайного цикла где-нибудь в цепочке областей, полагая, что вы устанавливаете свойство объекта.

Этап 8 описывает связывание параметров после установления диапазона функций. В принципе, параметры связаны со значениями и их имена добавляются в переменную среду.

Весь смысл держать две отдельные среды является то, что Подъемный механизм всегда использует переменную среды цепь в качестве рамки.

Идея состоит в том, что переменная или функция должны вести себя так, как если бы она была указана в верхней части текущего блока области видимости, поэтому, например, функция, объявленная внутри блока с блоком, не должна разрешать свои имена с помощью свойств объекта, с заявлением.

Откровенно говоря, это довольно спорный вопрос, поскольку спецификация ECMA не позволяет объявлять функции внутри блоков, хотя большинство реализаций делают, с результатами varrying.

Теперь для примера:

function foo(){ 
    var a={p:'p'}; 
    o={c:'c'}; 
} 

Ваша функция не содержит никаких with или catch заявления, поэтому цепочка областей внутри «Foo()» это просто список из двух переменных среды:

global (a bunch of DOM objects all seen as properties of 'window') 
    function foo (var a) 

после вызова Foo(),

  • a будет разрешен как локальная переменная foo, будет создан как объект с свойством p значения 'p' (и сбор мусора, как только вы покинете foo(), если только вам не удастся ссылаться на него из постоянной переменной).

  • o не будет найден в переменной окружения Foo, так что он будет пойман «поймать-все» глобального масштаба и, таким образом, решить, как (новое) свойство window объекта. Он создаст объект window.o.c со значением 'c'.

Отвечает ли это на ваш вопрос?

+0

Супер полезный ответ в целом для понимания разницы между лексической и переменной средой :) –

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