В чем разница между типами спецификаций Environment Record (Lexical Environment) и Reference в ECMAScript?

При чтении спецификации ECMAScript кажется, что Запись среды (компонент лексическое окружение) и Reference используется для определения того, к какой переменной/функции привязан Identifier. Другими словами, поиск фактического значения, представленного идентификатором.

Я заметил, что компонент Base value компонента Reference может содержать компонент Environment Record:

Компонент базового значения может быть неопределенным, объектом, логическим значением, строкой, символом, числом или записью среды.

Но мне не ясно, когда можно использовать Reference вместо контекста выполнения, просто читая Environment Record прямо из текущего Lexical Environment (как указано компонентом LexicalEnvironment running execution context).


ИЗМЕНИТЬ:

Приняв ответ @Bergi, я хотел добавить пару вещей, которые я не понял, на случай, если это поможет будущим читателям:

  1. Identifier lookups in ECMAScript always returns a Reference type
    • To resolve a variable/function name, we start at 8.3.2 ResolveBinding
    • Вы увидите, что сначала проверяется LexicalEnvironment running execution context (его запись среды).
    • Если совпадение не найдено, цепочка лексического окружения следует наружу до тех пор, пока не будет найдено совпадение (или нет).
    • Цепочка заканчивается на global environment, внешнее окружение которого null.
    • Как только совпадение найдено, возвращается тип Reference, для которого base value установлено значение имени в записи среды, которая соответствует
    • Если совпадений не найдено, возвращается Reference с base value из undefined.
    • Таким образом, поиск идентификатора всегда влечет за собой проверку записей среды и возврат типа Reference в конце.
  2. Reference's GetValue is only ever done after evaluation of an Expression
    • GetValue(ref) is used on a Reference to return its base value
    • Выполнив поиск в спецификации для "GetValue()", вы увидите, что это происходит только после оценки какого-то Expression
    • «Оценка Expression» означает просмотр того, что возвращает Reference и Expression
    • Из этого мы можем сделать вывод, что Expressions всегда оценивается как Reference (значение)
    • Примечание. Expression включает в себя широкий спектр других продуктов, таких как IdentifierReference, который глубоко вложен в Создание выражений

person Magnus    schedule 02.08.2018    source источник


Ответы (1)


Запись среды — это запись, содержащая несколько переменных.

Ссылка — это объект, представляющий что-то изменяемое, например свойство объекта или отдельную переменную.

Чтобы найти значение, как в console.log(value), вы можете просто найти имя «значение» в текущем лексическом окружении и получить оценку идентификатора. Но чтобы присвоить значение, как в value = 5, вам нужен идентификатор для оценки чего-то, что представляет место, где число может быть сохранено, и это тип Reference. Он содержит базу — запись (лексического окружения) — и идентификатор — имя конкретной переменной. Его можно разыменовать до значения (GetValue) , или вы можете присвоить ему новое значение (PutValue).

person Bergi    schedule 02.08.2018
comment
Просто интересно: в каком случае базовое значение ссылки не определено? - person Jonas Wilms; 02.08.2018
comment
@ДжонасВ. undefined.property, наверное? - person Bergi; 02.08.2018
comment
а GetValue тогда не получится? - person Jonas Wilms; 02.08.2018
comment
@JonasW.Да, точно - person Bergi; 02.08.2018
comment
Спасибо Берги. Если запись среды используется для идентификации фактической переменной/функции, с которой связан идентификатор, означает ли это, что каждая запись в записи среды на самом деле является ссылкой? Кроме того: если мы можем найти значение идентификатора с помощью записи среды, не должны ли мы также иметь возможность присваивать ему значение? - person Magnus; 02.08.2018
comment
@ДжонасВ. Подождите, нет, undefined.property бросает вызов, прежде чем он сможет оценить ссылку (аксессоры свойств используют RequireObjectCoercible). undefined базовые значения используются для неразрешимых ссылок (по крайней мере, так я сказал), т.е. когда вы ссылаетесь на необъявленную переменную - person Bergi; 02.08.2018
comment
@Magnus Нет, запись - это само хранилище (содержит память для каждой переменной). Вы можете сделать ссылку на него, но сама по себе она не является ссылкой (на что-то еще). - person Bergi; 02.08.2018
comment
@Magnus Да, мы, вероятно, могли бы это сделать, но это означает, что для Identifier = … и SomeOtherLeftHandSideExpression = … вам потребуются разные правила оценки в выражении присваивания. И это действительно создает проблемы при рассмотрении присвоения свойств, таких как superComplicated[Expression](withCall).property = …. Таким образом, это было упрощено, сказав, что каждое левое выражение оценивается как ссылка, а затем мы помещаем правостороннее значение в место, на которое указывает ссылка. Все дело в абстракции в спецификации. - person Bergi; 02.08.2018
comment
Правильно ли тогда, что ссылка используется только в присваиваниях, а во всех других случаях, когда мы хотим найти идентификатор, мы просто следуем цепочке лексического окружения? - person Magnus; 02.08.2018
comment
Ссылка по-прежнему нужна и для чтения переменной, потому что используется база. Например: var obj = { foo: function(){ console.log(this === obj); } }; with(obj) foo(); регистрирует true. - person loganfsmyth; 02.08.2018
comment
@Magnus При оценке выражения вы не знаете, будет ли оно целью присваивания или нет, поэтому вы всегда оцениваете его как ссылку. Затем, когда это была цель назначения, используется PutValue, но в противном случае, если вы просто хотите, используется значение GetValue. - person Bergi; 02.08.2018
comment
@Magnus Обратите внимание, что отслеживание цепочки лексического окружения (поиск области действия) происходит до создания ссылки — оно начинается при оценке идентификатора в текущем лексическом окружении. Затем ссылка будет указывать на конкретное имя в конкретной записи (которая может быть выше по объему, а не на запись текущей среды). - person Bergi; 02.08.2018
comment
@Magnus Также я солгал, когда сказал, что присваивания являются причиной использования ссылок, а не единственной причиной. Механизмы ссылок также используются для операторов typeof и delete, а также для вызовов методов. - person Bergi; 02.08.2018
comment
Аааа, я вижу, что ResolveBinding (8.3.2) возвращает GetIdentifierReference (8.1.2.1), который на самом деле всегда возвращает ссылку, базовым значением которой является вся запись среды, которая имеет привязку с данным идентификатором (именем), который мы пытались разрешить для . Другими словами, он всегда упаковывает результат (запись среды) в тип ссылки, а затем возвращает его. Я правильно понял? - person Magnus; 02.08.2018
comment
@Magnus Запись и имя, да. - person Bergi; 02.08.2018