Спецификация ECMAScript 5.1 с аннотациями

Поделиться

10 Исполняемый код и контексты исполнения #

10.1 Типы исполняемого кода #

Существует три типа исполняемого кода ECMAScript:

10.1.1 Код в строгом режиме #

Синтаксическая единица Программы на ECMAScript может обрабатываться с использованием синтаксиса и семантики либо в неограниченном unrestricted, либо в строгом strict режиме. При обработки синтаксической единицы с использованием строгого режима упомянутые три типа кода ECMAScript называются строгим глобальным кодом, строгим eval-кодом и строгим кодом функции. Код считается кодом в строгом режиме в следующих случаях:

10.2 Лексическое Окружение #

Lexical Environment Лексическое Окружение – это тип спецификации, который используется для определения связи между Identifiers Идентификаторами и отдельными переменными и функциями, на основе структуры лексической вложенности кода на ECMAScript. Лексическое Окружение состоит из Записи Окружения и возможной ссылки null на внешнее Лексическое Окружение. Обычно Лексическое Окружение ассоциируется с определёнными синтаксическими структурами кода на ECMAScript, такими как FunctionDeclaration, WithStatement Инструкция With или выражение Catch в TryStatement Инструкция Try, при этом каждый раз при обработке кода создаётся новое Лексическое Окружение.

Запись Окружения содержит привязки идентификатора, создаваемые в рамках ассоциированного с ним Лексического Окружения.

Для моделирования логической вложенности Лексических Окружений используется "внешняя ссылка окружения". Внешней ссылкой (внутреннего) Лексического Окружения является ссылка на Лексическое Окружение, которое логически окружает это внутреннее Лексическое Окружение. Конечно же, у внешнего Лексического Окружения может быть, в свою очередь, собственное внешнее Лексическое Окружение. Одно Лексическое Окружение может являться внешним окружением для нескольких внутренних Лексических Окружений. Например, если FunctionDeclaration содержит два вложенных FunctionDeclaration, то Лексическое Окружение текущего исполнения окружающей функции будет являться внешним Лексическим Окружением для Лексических Окружений каждой из вложенных функций.

Лексические Окружения и значения Записи Окружения являются исключительно механизмами спецификации; они не должны соответствовать каким-либо конкретным артефактам реализации ECMAScript. Программа на ECMAScript не может осуществлять прямого доступа к таким значениям или манипулировать ими напрямую.

10.2.1 Записи окружений #

В данной спецификации используется два вида значений Записей Окружения: декларативные записи окружения declarative environment records и объектные записи окружения object environment records. Декларативные записи окружения используются, чтобы определить действие таких синтаксических элементов языка ECMAScript, как FunctionDeclaration, VariableDeclaration и выражения Catch, которые напрямую ассоциируют привязки идентификатора со значениями языка ECMAScript. Объектные записи окружения используются для определения действия таких элементов ECMAScript, как Program и WithStatement, которые ассоциируют привязки идентификатора со свойствами некоторого объекта.

Для целей спецификации значения Записи Окружения можно рассматривать как существующие в простой объектно-ориентированной иерархии, где Environment Record представляет собой абстрактный класс с двумя конкретными подклассами: декларативной записью окружения и объектной записью окружения. Этот абстрактный класс включает абстрактные методы спецификации, определённые в Таблице 17. Для этих абстрактных методов имеются конкретные алгоритмы в каждом из конкретных подклассов.

Таблица 17. Абстрактные методы записей окружения

Метод

Назначение

HasBinding(N)

Определяет, имеет ли запись окружения привязку к идентификатору. Возвращает true, если имеет, и false, если не имеет. Текстом идентификатора является строковое значение N .

CreateMutableBinding(N, D)

Создаёт в записи окружения новую изменяемую привязку. Строковое значение N будет привязанным именем. Если необязательный булевый аргумент Dtrue, то привязка может быть впоследствии удалена.

SetMutableBinding(N,V, S)

Присваивает значение уже существующей в записи окружения изменяемой привязки. Строковое значение N будет привязанным именем. V является значением привязки; оно может быть значением любого языкового типа ECMAScript. S – булев флаг. Еcли Strue, и привязка не может быть установлена, то сгенерировать исключение TypeError. S используется для обозначения ссылок в строгом режиме.

GetBindingValue(N,S)

Возвращает из записи окружения значение уже существующей привязки. Текстом связанного имени является строковое значение N. S используется для обозначения ссылок в строгом режиме. Ели Strue, и привязки не существует или привязка не инициализирована, сгенерировать исключение TypeError.

DeleteBinding(N)

Удаляет привязку из записи окружения. Текстом связанного имени является строковое значение N. Если привязка для N существует, удалить привязку и вернуть true. Если привязка существует, но не может быть удалена, то вернуть false. Если привязки не существует, то вернуть true.

ImplicitThisValue()

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

10.2.1.1 Декларативные записи окружения #

Каждая декларативная запись окружения ассоциирована областью видимости программы на ECMAScript, которая содержит объявления переменных и/или объявления функций. Декларативная запись окружения содержит привязки для идентификаторов, определённых в рамках её области видимости.

В дополнение к изменяемым привязкам, которые поддерживаются всеми записями окружения, декларативные записи окружения предусматривают и неизменяемые привязки. Неизменяемая привязка – это привязка, в которой связь, установленная между идентификатором и значением, уже не может быть изменена. Создание и инициализация неизменяемых привязок представляют собой отдельные шаги, поэтому такие привязки вполне могут существовать как в инициализированном, так и в неинициализированном виде. Кроме абстрактных методов спецификации записи окружения, декларативные записи окружения поддерживают методы, перечисленные в Таблице 18:

Таблица 18. Дополнительные методы декларативных записей окружения

Метод

Назначение

CreateImmutableBinding(N)

Создаёт в записи окружения новую, но не инициализированную неизменяемую привязку. Текстом связанного имени является строковое значение N.

InitializeImmutableBinding(N,V)

Присваивает значение уже существующей в записи окружения, но не инициализированной неизменяемой привязки. Строковое значение N будет именем. V будет значением любого языкового типа ECMAScript.

Поведение конкретных методов спецификации для Декларативных записей окружения определяется следующими алгоритмами:

10.2.1.1.1 HasBinding(N) #

Конкретный метод записи окружения HasBinding Имеет привязку для декларативных записей окружения просто определяет, является ли идентификатор аргумента одним из идентификаторов, связанных этой записью:

  1. Пусть envRec – декларативная запись окружения, для которой вызывается этот метод.

  2. Если envRec имеет привязку к имени, которое представляет собой значение N, вернуть true.

  3. Если оно не имеет такой привязки, то вернуть false.

10.2.1.1.2 CreateMutableBinding (N, D) #

Конкретный метод записи окружения CreateMutableBinding Создать изменяемую привязку для записей декларативного окружения создаёт для имени N новую изменяемую привязку, которая инициализируется с присвоением значения undefined. До этого момента в этой записи окружения для N не должно существовать привязки. Если имеется булевый аргумент D, и при этом его значение – true, то эта новая привязка помечается как удаляемая.

  1. Пусть envRec – декларативная запись окружения, для которой вызывается этот метод.

  2. Утверждается: у envRec еще нет привязки для N.

  3. Создать изменяемую привязку в envRec для N и установить её связанное значение как undefined. Если D – true, то записать, что эта новая привязка может быть удалена вызовом DeleteBinding.

10.2.1.1.3 SetMutableBinding (N,V,S) #

Конкретный метод записи окружения SetMutableBinding Установить значение изменяемой привязки для декларативных записей окружения пытается изменить связанное значение текущей привязки идентификатора, имя которого представляет собой значение аргумента N, на значение аргумента V. Привязка для N уже должна существовать. Если привязка является неизменяемой привязкой, и при этом Strue, то будет сгенерировано исключение TypeError.

  1. Пусть envRec – декларативная запись окружения, для которой вызывается этот метод.

  2. Утверждается: у envRec уже должна быть привязка для N.

  3. Если привязка для N в envRec является изменяемой привязкой, то изменить её связанное значение на V.

  4. Иначе, это является попыткой изменить значение неизменяемой привязки, поэтому, если Strue, то сгенерировать исключение TypeError.

10.2.1.1.4 GetBindingValue(N,S) #

Конкретный метод записи окружения GetBindingValue Получить значение привязки для декларативных записей окружения просто возвращает значение его связанного идентификатора, имя которого представляет собой значение аргумента N. Эта привязка уже должна существовать. Если Strue, и привязка является неинициализированной неизменяемой привязкой, то сгенирировать исключение ReferenceError.

  1. Пусть envRec – декларативная запись окружения, для которой вызывается этот метод.

  2. Утверждается: у envRec уже есть привязка для N.

  3. Если привязка для N в записи окружения envRec является неинициализированной неизменяемой привязкой, то

    1. Если Sfalse, вернуть значение undefined, в противном случае сгенерировать исключение ReferenceError.

  4. Иначе, вернуть значение, в настоящее время привязанное к N в записи окружения envRec.

10.2.1.1.5 DeleteBinding (N) #

Конкретный метод записи окружения для декларативных записей окружения DeleteBinding Удалить привязку может удалять только те привязки, которые явно обозначены как удаляемые.

  1. Пусть envRec – декларативная запись окружения, для которой вызывается этот метод.

  2. Если envRec не имеет привязки к имени, которое является значением N, вернуть true.

  3. Если привязка для N в envRec не может быть удалена, вернуть false.

  4. Удалить привязку для N из envRec.

  5. Вернуть true.

10.2.1.1.6 ImplicitThisValue() #

Декларативные записи окружения всегда возвращают значение undefined в качестве их ImplicitThisValue Явное значение This.

  1. Вернуть undefined.

10.2.1.1.7 CreateImmutableBinding (N) #

Конкретный метод записи окружения CreateImmutableBinding Создать неизменяемую привязку для записей декларативного окружения создаёт для имени N новую неизменяемую привязку, которая инициализируется с присвоением значения undefined. До этого момента в этой записи окружения для N не должно существовать привязки.

  1. Пусть envRec – декларативная запись окружения, для которой вызывается этот метод.

  2. Утверждается: у envRec еще нет привязки для N.

  3. Создать в envRec для N неизеняемую привязку и записать, что она является неинициализированной.

10.2.1.1.8 InitializeImmutableBinding (N,V) #

Конкретный метод записи окружения InitializeImmutableBinding Инициализировать неизменяемую привязку для декларативных записей окружения используется для присвоения значения аргумента V связанному значению текущей привязки идентификатора, имя которого – значение аргумента N. Неинициализированная неизменяемая привязка для N уже должна существовать.

  1. Пусть envRec – декларативная запись окружения, для которой вызывается этот метод.

  2. Утверждается: у envRec должна быть неинициализированная неизменяемая привязка для N.

  3. Присвоить V связанному значению для N в envRec.

  4. Записать, что неизменяемая привязка для N в envRec была инициализирована.

10.2.1.2 Объектные записи окружения #

Каждая объектная запись окружения связана с объектом, который называется её объектом привязки binding object. Объектная запись окружения содержит набор имён идентификаторов, которые непосредственно соответствуют именам свойств её объекта привязки. Имена свойств, которые не представляют собой IdentifierName Имя идентификатора, не входят в этот набор связанных идентификаторов. В этот набор входят как собственные, так и наследуемые свойства, независимо от установок их атрибута [[Enumerable]]. Поскольку свойства могут динамически добавляться к объектам и удаляться из них, теоретически возможно изменение набора идентификаторов, связанных объектной записью окружения, в результате побочного эффекта какой-либо операции, в процессе которой происходит добавление или удаление свойств. Привязки, создаваемые в результате такого побочного эффекта, считаются изменяемыми привязками, даже если атрибут Writable соответствующего свойства имеет значение false. Неизменяемых привязок для объектных записей окружения не существует.

Объектные записи окружения могут быть сконфигурированы таким образом, чтобы предоставлять свой объект привязки в качестве значения this при вызове функции. Эта возможность используется для задания поведения привязок, порожденных инструкцией With (12.10). Данная возможность контролируется булевым значением provideThis задать This, которое ассоциируется с каждой объектной записью окружения. По умолчанию значение provideThis для любой объектной записи окружения – false.

Поведение конкретных методов спецификации для объектных записей окружения определяется следующими алгоритмами:

10.2.1.2.1 HasBinding(N) #

Конкретный метод записи окружения HasBinding Имеет привязку для объектных записей окружения определяет, есть ли у ассоциированного объекта привязки свойство, название которого является значением аргумента N:

  1. Пусть envRec – объектная запись окружения, для которой вызывается этот метод.

  2. Пусть bindings будет объектом привязки для envRec.

  3. Вернуть результат вызова внутреннего метода [[HasProperty]] для bindings с передачей N в качестве имени свойства.

10.2.1.2.2 CreateMutableBinding (N, D) #

Конкретный метод записи окружения CreateMutableBinding Создать изменяемую привязку для объектных записей окружения создаёт в ассоциированном с записью окружения объекте привязки свойство, имя которого является строковым значением, и инициализирует его, присваивая значение undefined. До этого момента в объекте привязки не должно существовать свойства с именем N. Если имеется булевый аргумент D, который имеет значение true, то атрибуту [[Configurable]] созданного нового свойства присваивается значение true, в противном случае ему присваивается значение false.

  1. Пусть envRec – объектная запись окружения, для которой вызывается этот метод.

  2. Пусть bindings будет объектом привязки для envRec.

  3. Утверждается: Результат вызова внутреннего метода [[HasProperty]] для bindings, с передачей N в качестве имени свойства, составляет false.

  4. Если D – true, тогда пусть configValue будет true, в противном случае пусть configValue будет false.

  5. Вызвать внутренний метод [[DefineOwnProperty]] для bindings, передавая в качестве аргументов N, Property Descriptor {[[Value]]:undefined, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: configValue} и true.

10.2.1.2.3 SetMutableBinding (N,V,S) #

Конкретный метод записи окружения SetMutableBinding Установить значение изменяемой привязки для объектных записей окружения предпринимает попытку присвоить значение аргумента V значению свойства объекта привязки (ассоциированного с записью окружения), имя которого является значением аргумента N. Свойство с именем N уже должно существовать, но если его не существует, или если оно в данный момент не является перезаписываемым, обработка ошибок определяется значением булевого аргумента S.

  1. Пусть envRec – объектная запись окружения, для которой вызывается этот метод.

  2. Пусть bindings будет объектом привязки для envRec.

  3. Вызвать внутренний метод [[Put]] для bindings с аргументами N, V и S.

10.2.1.2.4 GetBindingValue(N,S) #

Конкретный метод записи окружения GetBindingValue Получить значение привязки для объектных записей окружения возвращает значение свойства для своего ассоциированного объекта привязки, имя которого представляет собой строковое значение идентификатора аргумента N. Это свойство уже должно существовать, но если его не существует, то результат зависит от значения аргумента S:

  1. Пусть envRec – объектная запись окружения, для которой вызывается этот метод.

  2. Пусть bindings будет объектом привязки для envRec.

  3. Пусть value значение будет результатом вызова внутреннего метода [[HasProperty]] для bindings с передачей N в качестве имени свойства.

  4. Если valuefalse, то

    1. Если Sfalse, то вернуть значение undefined, в противном случае сгенерировать исключение ReferenceError.

  5. Вернуть результат вызова внутреннего метода [[Get]] для bindings с передачей N в качестве аргумента.

10.2.1.2.5 DeleteBinding (N) #

Конкретный метод записи окружения DeleteBinding Удалить привязку для объектных записей окружения может удалять только те привязки, которые соответствуют свойствам объекта окружения, у которого атрибут [[Configurable]] имеет значение true.

  1. Пусть envRec – объектная запись окружения, для которой вызывается этот метод.

  2. Пусть bindings будет объектом привязки для envRec.

  3. Вернуть результат вызова внутреннего метода [[Delete]] для bindings, передавая в качестве аргументов N и false.

10.2.1.2.6 ImplicitThisValue() #

В качестве своего значения ImplicitThisValue объектные записи окружения возвращают undefined, кроме случаев, когда их флаг provideThis равен true.

  1. Пусть envRec – объектная запись окружения, для которой вызывается этот метод.

  2. Если флаг provideThis для envRec составляет true, вернуть объект привязки для envRec.

  3. Иначе вернуть undefined.

10.2.2 Операции Лексического Окружения #

Для работы с лексическими окружениями в данной спецификации используются следующие абстрактные операции:

10.2.2.1 GetIdentifierReference (lex, name, strict) #

При вызове абстрактной операции GetIdentifierReference Получить ссылку на идентификатор используются Лексическое Окружение lex, строка идентификатора name и булев флаг strict. Значением lex может быть null. При вызове этой абстрактной операции выполняются следующие шаги:

  1. Если lex имеет значение null, то

    1. Вернуть значение типа Reference со значением базы undefined, с именем ссылки name и с флагом строгого режима strict.

  2. Пусть envRec будет записью окружения lex.

  3. Пусть exists существует будет результатом вызова конкретного метода HasBinding(N) для envRec с передачей name в качестве аргумента N.

  4. Если exists true, то

    1. Вернуть значение типа Reference со значением базы envRec, с именем ссылки name и с флагом строгого режима strict.

  5. Иначе

    1. Пусть outer внешний будет значением внешней ссылки окружения для lex.

    2. Вернуть результат вызова абстрактной операции GetIdentifierReference, передавая в качестве аргументов outer, name и strict.

10.2.2.2 NewDeclarativeEnvironment (E) #

При вызове абстрактной операции NewDeclarativeEnvironment Новое декларативное окружение либо с Лексическим Окружением, либо с null в качестве аргумента E выполняются следующие шаги:

  1. Пусть env будет новым Лексическим Окружением.

  2. Пусть envRec будет новой декларативной записью окружения, не содержащей привязок.

  3. Записи Окружения для env присвоить envRec.

  4. Ссылке на внешнее Лексическое Окружение для env присвоить E.

  5. Вернуть env.

10.2.2.3 NewObjectEnvironment (O, E) #

При вызове абстрактной операции NewObjectEnvironment Новое объектное окружение с объектом O и Лексическим Окружением E (или null) в качестве аргаментов выполняются следующие шаги:

  1. Пусть env будет новым Лексическим Окружением.

  2. Пусть envRec будет новой объектной записью окружения, содержащей O в качестве объекта привязки.

  3. Записи Окружения для env присвоить envRec.

  4. Ссылке на внешнее Лексическое Окружение для env присвоить E.

  5. Вернуть env.

10.2.3 Глобальное окружение #

Глобальное окружение представляет собой уникальное Лексическое Окружение, создаваемое перед выполнением любого кода на ECMAScript. Запись Окружения глобального окружения представляет собой объектную запись окружения, объект привязки которой является глобальным объектом (15.1). Ссылка на внешнее окружение глобального окружения равна null.

При выполнение кода на ECMAScript к глобальному объекту могут добавляться дополнительные свойства, а исходные свойства могут изменяться.

10.3 Контексты исполнения #

Когда контроль переходит к исполняемому коду на ECMAScript, управление вступает в контекст исполнения. Активные контексты исполнения логически образуют стек. Контекст исполнения, находящийся наверху этого логического стека, является активным контекстом исполнения. Всякий раз при переходе управления от исполняемого кода, ассоциированного с текущим контекстом исполнения, к исполняемому коду, не ассоциированному с этим контекстом исполнения, создаётся новый контекст исполнения. Этот вновь созданный контекст исполнения помещается наверх стека и становится активным контекстом исполнения.

Всякий контекст исполнения содержит то состояние, которое необходимо для отслеживания процесса исполнения ассоциированного кода. Кроме того, каждый контекст исполнения имеет компоненты состояния, перечисленные в Таблице 19.

Таблица 19. Компоненты состояния контекста исполнения.

Компонент

Назначение

LexicalEnvironment

Определяет Лексическое Окружение, используемое для разрешения ссылок на идентификаторы, создаваемых кодом в данном контексте исполнения.

VariableEnvironment

Определяет Лексическое Окружение, в котором запись окружения содержит привязки, создаваемые посредством VariableStatements и FunctionDeclarations в данном контексте исполнения.

ThisBinding

Значение, связанное с ключевым словом this в коде на ECMAScript, ассоциированным с данным контекстом исполнения.

Компоненты LexicalEnvironment и VariableEnvironment всегда являются Лексическими Окружениями. При создании контекста исполнения, его компоненты LexicalEnvironment и VariableEnvironment изначально имеют одинаковое значение. Значение компонента VariableEnvironment никогда не меняется, а LexicalEnvironment может меняться во время выполнения кода в контексте исполнения.

Чаще всего алгоритмы, представленные в данной спецификации, непосредственно манипулируют только активным контекстом исполнения, расположенным наверху стека контекстов исполнения. Поэтому, если термины “LexicalEnvironment”, “VariableEnvironment” и “ThisBinding” используются без уточнения, значит, они относятся к компонентам активного контекста исполнения.

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

10.3.1 Разрешение идентификатора #

Разрешение идентификатора представляет собой процесс определения привязки для Identifier с использованием Лексического Окружения активного контекста исполнения. Во время выполнения кода на ECMAScript синтаксическое правило PrimaryExpression : Identifier вычисляется с использованием следующего алгоритма:

  1. Пусть env будет Лексическое Окружение активного контекста исполнения.

  2. Если синтаксическое правило, вычисление которого производится, содержится в коде в строгом режиме, то пусть strict будет true, иначе пусть strict будет false.

  3. Вернуть результат вызова функции GetIdentifierReference, передавая в качестве аргументов env, Identifier и strict.

Результат вычисления идентификатора всегда имеет значение типа Reference, при этом его компонент имени по ссылке равен строке Identifier.

10.4 Установление контекста исполнения #

Исполнение глобального кода или кода с использованием функции eval (15.1.2.1) устанавливает новый контекст исполнения и входит в него. Каждый вызов функции в коде на ECMAScript (13.2.1) также устанавливает новый контекст исполнения и входит в него, даже если функция вызывает себя рекурсивно. При каждом возврате производится выход из контекста исполнения. Сгенерированное исключение также может выйти из одного или нескольких контекстов исполнения.

Когда управление входит в контекст исполнения, устанавливается компонент ThisBinding контекста исполнения, определяются его компоненты VariableEnvironment и начальный LexicalEnvironment, и производится создание привязки для объявлений (10.5). Способ выполнения этих действий зависит от типа кода, в который входит управление.

10.4.1 Вход в глобальный код #

При вхождении управления в контекст исполнения глобального кода выполняются следующие шаги:

  1. Инициализировать контекст исполнения с использованием глобального кода, как описано в пункте 10.4.1.1.

  2. Произвести Инстанциирование привязки объявлений, в соответствии с описанием в пункте 10.5 с использованием глобального кода.

10.4.1.1 Исходный глобальный контекст исполнения #

Для инициализации глобального контекста исполнения для кода C на ECMAScript выполняются следующие шаги:

  1. Присвоить VariableEnvironment значение Global Environment.

  2. Присвоить LexicalEnvironment значение Global Environment.

  3. Присвоить ThisBinding значение глобального объекта.

10.4.2 Вход в Eval-код #

При вхождении управления в контекст исполнения eval-кода выполняются следующие шаги:

  1. Если контекст вызова отсутствует или eval-код вызывается не посредством прямого вызова (15.1.2.1.1) функции eval, то

    1. Инициализировать контекст исполнения, как если бы он был глобальным контекстом исполнения, используя eval-код в качестве C, в соответствии с описанием в пункте 10.4.1.1.

  2. Иначе

    1. Присвоить ThisBinding то же значение, что и у ThisBinding вызывающего контекста исполнения.

    2. Присвоить LexicalEnvironment такое же значение, что и у LexicalEnvironment вызывающего контекста исполнения.

    3. Присвоить VariableEnvironment то же значение, что и у VariableEnvironment вызывающего контекста исполнения.

  3. Если eval-код представляет собой строгий код, то

    1. Путь strictVarEnv Строгое окружение переменной будет результатом вызова абстрактной операции NewDeclarativeEnvironment с передачей в качестве аргумента LexicalEnvironment.

    2. Присвоить LexicalEnvironment значение strictVarEnv.

    3. Присвоить VariableEnvironment значение strictVarEnv.

  4. Произвести Инстанциирование привязки объявления, в соответствии с описанием в пункте 10.5 с использованием eval-кода.

10.4.2.1 Ограничения строгого режима #

Eval-код не может инстанциировать привязки переменных или привязки функции в окружении переменных вызывающего контекста, вызвавшего eval, если код вызывающего контекста или eval-код является строгим кодом. Вместо этого такие привязки инстанцируются в новом VariableEnvironment, доступ к которому имеет только eval-код.

10.4.3 Вход в код функции #

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

  1. Если код функции представляет собой строгий код, то ThisBinding присвоить значение thisArg Аргумент this.

  2. Иначе, если thisArgnull или undefined, то ThisBinding присвоить значение глобального объекта.

  3. Иначе, если Тип(thisArg) не объект, то ThisBinding присвоить значение ToObject(thisArg).

  4. Иначе, ThisBinding присвоить значение thisArg.

  5. Пусть localEnv Локальное окружение будет результатом вызова NewDeclarativeEnvironment с передачей в качестве аргумента значения внутреннего свойства [[Scope]] для F.

  6. Присвоить LexicalEnvironment значение localEnv.

  7. Присвоить VariableEnvironment значение localEnv.

  8. Пусть code будет значением внутреннего свойства [[Code]] для F.

  9. Выполнить Инстанциирование привязки объявления, используя code и argumentList для кода функции, в соответствии с описанием в пункте 10.5.

10.5 Инстанциирование привязки объявления #

У каждого контекста исполнения есть ассоциированное VariableEnvironment Окружение Переменных. Переменные и функции, объявленные в коде на ECMAScript, выполнение которого производится в контексте исполнения, добавляются в качестве привязок в Запись Окружения этого Окружения переменных. Если речь идет о коде функции, то в качестве привязок в эту Запись Окружения добавляются и параметры.

От типа кода на ECMAScript, исполняемого контекстом исполнения, зависит, какая Запись Окружения используется для привязки объявления, а также тип объявления. Во всем остальном поведение является типовым. При входе в контекст исполнения привязки создаются в окружении переменных в соответствии с приведенным ниже описанием, при этом используется предоставляемый вызывающим кодом code и, если это код функции, Список аргументов args:

  1. Пусть env будет компонентом записи окружения для VariableEnvironment активного контекста исполнения.

  2. Если codeeval-код, то пусть значение configurableBindings Конфигурируемые привязки будет true, иначе пусть configurableBindings будет false.

  3. Если codeкод в строгом режиме, то пусть значение strict (строгий) будет true, иначе пусть strict будет false.

  4. Если code код функции, то

    1. Пусть func будет функцией, внутренний метод [[Call]] которой инициировал выполнение кода code. Пусть names будет значением внутреннего метода [[FormalParameters]] для func.

    2. Пусть argCount будет количеством элементов в args.

    3. Пусть n будет числом 0.

    4. Для каждой строки argName в names по порядку списка выполняется следующее:

      1. Пусть n будет текущим значением n плюс 1.

      2. Если n больше чем argCount, пусть v будет undefined, в противном случае пусть v будет значением n-нного элемента в args.

      3. Пусть argAlreadyDeclared Аргумент уже объявлен будет результатом вызова конкретного метода HasBinding для env, с передачей в качестве аргумента argName.

      4. Если argAlreadyDeclared false, то вызвать конкретный метод CreateMutableBinding для env, с передачей в качестве аргумента argName.

      5. Вызвать конкретный метод SetMutableBinding для env, передавая в качестве аргументов argName, v и strict.

  1. Для каждого FunctionDeclaration f в code, по порядку исходного текста выполняется следующее:

    1. Пусть fn будет Identifier в FunctionDeclaration f.

    2. Пусть fo будет результатом инстанциирования FunctionDeclaration f, в соответствии в описанием приведенным в Главе 13.

    3. Пусть funcAlreadyDeclared Функция уже объявлена будет результатом вызова конкретного метода HasBinding для env, с передачей в качестве аргумента fn.

    4. Если funcAlreadyDeclared false, то вызвать конкретный метод CreateMutableBinding для env, с передачей в качестве аргументов fn и configurableBindings.

    5. Иначе, если env – компонент записи окружения глобального окружения, то

      1. Пусть go будет глобальным объектом.

      2. Пусть existingProp Существующее свойство будет результатом вызова внутреннего метода [[GetProperty]] для go с аргументом fn.

      3. Если existingProp .[[Configurable]] – true, то

        1. Вызвать внутренний метод [[DefineOwnProperty]] для go, передавая в качестве аргументов fn, Property Descriptor {[[Value]]:undefined, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: configurableBindings } и true.

      4. Иначе, если IsAccessorDescrptor(existingProp) или existingProp не имеет значений атрибута {[[Writable]]: true, [[Enumerable]]: true}, то

        1. Сгенерировать исключение TypeError.

    6. Вызвать конкретный метод SetMutableBinding для env, передавая в качестве аргументов fn, fo и strict.

  1. Пусть argumentsAlreadyDeclared Аргументы уже объявлены будет результатом вызова конкретного метода HasBinding для env, с передачей "arguments" в качестве аргумента.

  2. Если codeкод функции, и argumentsAlreadyDeclared false, то

    1. Пусть argsObj будет результатом вызова абстрактной операции CreateArgumentsObject (10.6) с передачей в качестве аргументов func, names, args, env и strict.

    2. Если strict true, то

      1. Вызвать конкретный метод CreateImmutableBinding для env, передавая в качестве аргумента строку "arguments".

      2. Вызвать конкретный метод InitializeImmutableBinding для env, передавая в качестве аргументов "arguments" и argsObj.

    3. Иначе

      1. Вызвать конкретный метод CreateMutableBinding для env, передавая в качестве аргумента строку "arguments".

      2. Вызвать конкретный метод SetMutableBinding для env, передавая в качестве аргументов "arguments", argsObj и false.

  1. Для каждого VariableDeclaration и VariableDeclarationNoIn d в code, по порядку исходного текста выполняется следующее:

    1. Пусть dn будет Identifier в d.

    2. Пусть varAlreadyDeclared Переменная уже объявлена будет результатом вызова конкретного метода HasBinding для env, с передачей в качестве аргумента dn.

    3. Если varAlreadyDeclared false, то

      1. Вызвать конкретный метод CreateMutableBinding для env, передавая в качестве аргументов dn и configurableBindings.

      2. Вызвать конкретный метод SetMutableBinding для env, передавая в качестве аргументов dn, undefined и strict.

10.6 Объект аргументов #

При входе управления в контекст исполнения для кода функции создаётся объект аргументов, за исключением случаев, если (в соответствии с описанием в пункте 10.5) идентификатор arguments встречается в качестве Identifier в списке FormalParameterList Список формальных параметров этой функции, или если он встречается в качестве Identifier для VariableDeclaration или FunctionDeclaration, содержащихся в коде функции.

Объект аргументов создаётся посредством вызова абстрактной операции CreateArgumentsObject (Созать объект аргументов) с аргументами func – объектом функции, код которой подлежит выполнению, namesСписком, содержащим имена формальных параметров функции, args – фактическими параметрами, передаваемыми во внутренний метод [[Call]], env – окружением переменной для кода функции и strict – булевым значением, указывающим, верно ли, что код функциистрогий код. При вызове абстрактной операции CreateArgumentsObject выполняются следующие шаги:

  1. Пусть len будет количеством элементов в args.

  2. Пусть obj будет результатом создания нового объекта ECMAScript.

  3. Установить все внутренние методы для obj в соответствии с описанием в пункте 8.12.

  4. Присвоить внутреннему свойству [[Class]] для obj значение "Arguments".

  5. Пусть Object будет стандартным встроенным конструктором объекта (15.2.2).

  6. Присвоить внутреннему свойству [[Prototype]] для obj значение стандартного встроенного объекта-прототипа Object (15.2.4).

  7. Вызвать внутренний метод [[DefineOwnProperty]] для obj, передавая в качестве аргументов "length", Property Descriptor {[[Value]]: len, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true} и false.

  8. Пусть map будет результатом создания нового объекта, как если бы этот объект был создан выражением new Object(), где Object является стандартным встроенным конструктором с этим именем.

  9. Пусть mappedNames будет пустой Список.

  10. Пусть indx = len - 1.

  11. Повторять до тех пор, пока indx >= 0,

    1. Пусть val будет элементом args в позиции indx списка, начинающегося с позиции 0.

    2. Вызвать внутренний метод [[DefineOwnProperty]] для obj, передавая в качестве аргументов ToString(indx), property descriptor {[[Value]]: val, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.

    3. Если indx меньше чем количество элементов в names, то

      1. Пусть name будет элементом names в позиции indx списка, начинающегося с позиции 0.

      2. Если strictfalse, и name не является элементом mappedNames, то

        1. Добавить name в качестве элемента списка mappedNames.

        2. Пусть g будет результатом вызова абстрактной операции MakeArgGetter с аргументами name и env.

        3. Пусть p будет результатом вызова абстрактной операции MakeArgSetter с аргументами name и env.

        4. Вызвать внутренний метод [[DefineOwnProperty]] для map, передавая в качестве аргументов ToString(indx), Property Descriptor {[[Set]]: p, [[Get]]: g, [[Configurable]]: true} и false.

    4. Пусть indx = indx - 1

  12. Если список mappedNames не пуст, то

    1. Присвоить внутреннему свойству [[ParameterMap]] для obj значение map.

    2. Присвоить внутренним методам [[Get]], [[GetOwnProperty]], [[DefineOwnProperty]] и [[Delete]] для obj определения, приведенные ниже.

  13. Если strict false, то

    1. Вызвать внутренний метод [[DefineOwnProperty]] для obj, передавая в качестве аргументов "callee", property descriptor {[[Value]]: func, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true} и false.

  14. Иначе, strict является true, поэтому

    1. Пусть thrower будет объектом функции [[ThrowTypeError]] (13.2.3).

    2. Вызвать внутренний метод [[DefineOwnProperty]] для obj с аргументами "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false} и false.

    3. Вызвать внутренний метод [[DefineOwnProperty]] для obj с аргументами "callee", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false} и false.

  15. Вернуть obj.

Абстрактная операция MakeArgGetter, вызываемая со строкой name и записью окружения env, создаёт объект функции, который при выполнении возвращает значение, привязанное к name в env. Эта абстрактная операция выполняет следующие шаги:

  1. Пусль body будет результатом конкатенации строк "return", name и ";"

  2. Вернуть результат создания объекта функции, как описано в пункте 13.2, не используя FormalParameterList, используя body в качестве FunctionBody, env в качестве Scope и true в качестве Strict.

Абстрактная операция MakeArgSetter, вызываемая со строкой name и записью окружения env, создаёт объект функции, который при выполнении устанавливает значение, привязанное к name в env. Эта абстрактная операция выполняет следующие шаги:

  1. Пусть param будет результатом конкатенации строки name со строкой "_arg"

  2. Пусть body будет строкой "<name> =<param>;" при этом вместо <name> – значение name, а вместо <param> – значение param.

  3. Вернуть результат создания объекта функции, как описано в пункте 13.2, используя Список, содержащий единичный строковый param в качестве FormalParameterList, body в качестве FunctionBody, env в качестве Scope и true в качестве Strict.

Внутренний метод [[Get]] объекта аргументов для функции не в строгом режиме с формальными параметрами, вызываемый с именем свойства P, выполняет следующие шаги:

  1. Пусть map будет значением внутреннего свойства [[ParameterMap]] объекта аргументов.

  2. Пусть isMapped будет результатом вызова внутреннего метода [[GetOwnProperty]] для map с передачей P в качестве аргумента.

  3. Если значение isMappedundefined, то

    1. Пусть v будет результатом вызова внутреннего метода по умолчанию [[Get]] (8.12.3) для объекта аргументов с передачей P в качестве аргумента.

    2. Если P"caller" и v – объект функции в строгом режиме, сгенерировать исключение TypeError.

    3. Вернуть v.

  4. Иначе, map содержит соответствие формальному параметру для P, поэтому

    1. Вернуть результат вызова внутреннего метода [[Get]] для map с передачей P в качестве аргумента.

Внутренний метод [[GetOwnProperty]] объекта аргументов для функции не в строгом режиме с формальными параметрами, вызываемый с именем свойства P, выполняет следующие шаги:

  1. Пусть desc будет результатом вызова внутреннего метода по умолчанию [[GetOwnProperty]] (8.12.1) для объекта аргументов с передачей P в качестве аргумента.

  2. Если desc – undefined, вернуть desc.

  3. Пусть map будет значением внутреннего свойства [[ParameterMap]] объекта аргументов.

  4. Пусть isMapped будет результатом вызова внутреннего метода [[GetOwnProperty]] для map с передачей P в качестве аргумента.

  5. Если значение isMapped – не undefined, то

    1. Присвоить desc.[[Value]] результат вызова внутреннего метода [[Get]] для map, передавая P в качестве аргумента.

  6. Вернуть desc.

Внутренний метод [[DefineOwnProperty]] объекта аргументов для функции не в строгом режиме с формальными параметрами, вызываемый с именем свойства P, дескриптором свойства Desc и булевым флагом Throw, выполняет следующие шаги:

  1. Пусть map будет значением внутреннего свойства [[ParameterMap]] объекта аргументов.

  2. Пусть isMapped будет результатом вызова внутреннего метода [[GetOwnProperty]] для map с передачей P в качестве аргумента.

  3. Пусть desc будет результатом вызова внутреннего метода по умолчанию [[GetOwnProperty]] (8.12.9) для объекта аргументов с передачей P, Desc и false в качестве аргументов.

  4. Если allowed false, то

    1. Если Throw true, то сгенерировать исключение TypeError, иначе вернуть false.

  5. Если значение isMapped – не undefined, то

    1. Если IsAccessorDescriptor(Desc) – true, то

      1. Вызвать внутренний метод [[Delete]] для map, передавая в качестве аргументов P и false.

    2. Иначе

      1. Если имеется Desc.[[Value]], то

        1. Вызвать внутренний метод [[Put]] для map, передавая в качестве аргументов P, Desc.[[Value]] и Throw.

      2. Если имеетс Desc.[[Writable]], и его значение – false, то

        1. Вызвать внутренний метод [[Delete]] для map, передавая в качестве аргументов P и false.

  6. Вернуть true.

Внутренний метод [[Delete]] объекта аргументов для функции не в строгом режиме с формальными параметрами, вызываемый с именем свойства P и булевым флагом Throw, выполняет следующие шаги:

  1. Пусть map будет значением внутреннего свойства [[ParameterMap]] объекта аргументов.

  2. Пусть isMapped будет результатом вызова внутреннего метода [[GetOwnProperty]] для map с передачей P в качестве аргумента.

  3. Пусть result будет результатом вызова внутреннего метода по умолчанию [[Delete]] (8.12.7) для объекта аргументов с передачей P и Throw в качестве аргументов.

  4. Если resulttrue и значение isMapped – не undefined, то

    1. Вызвать внутренний метод [[Delete]] для map, передавая в качестве аргументов P и false.

  5. Вернуть result.

ПРИМЕЧАНИЕ 1 Для функций в нестрогом режиме именованные свойства данных индекса массива (определение которого приводится в пункте 15.4) для объекта аргументов, у которого числовые именованные значения меньше, чем число формальных параметров соответствующего объекта функции, изначально разделяют свои значения с соответствующими привязками к аргументу в контексте исполнения этой функции. Это означает, что при изменении свойства изменяется соответствующее значение привязки к аргументу, и наоборот. Это соответствие нарушается, если такое свойство будет удалено и затем переопределено, или если это свойство будет изменено и станет свойством аксессора. Для функций в строгом режиме значения свойств объекта аргументов являются просто копией аргументов, переданных в функцию. Между значениями свойств и значениями формальных параметров нет динамического связывания.

ПРИМЕЧАНИЕ 2 Объект ParameterMap и значения его свойств используются в качестве инструмента для определения соответствия объекта аргументов привязкам к аргументу. Доступ к объекту ParameterMap и к объектам, представляющим собой значения его свойств, невозможен непосредственно из кода на ECMAScript. Для реализации заданной семантики нет необходимости в том, чтобы реализация на ECMAScript фактически создавала или использовала эти объекты.

ПРИМЕЧАНИЕ 3 Объекты аргументов для функций в строгом режиме определяют неконфигурируемые свойства аксессора, называемые "caller" и "callee", которые при доступе генерируют исключение TypeError. Свойство "callee" имеет более специфичное значение для функций в нестрогом режиме. А свойство "caller" всегда обеспечивалось некоторыми реализациями ECMAScript как расширение, зависящее от реализации. Определение этих свойств в строгом режиме существует для гарантии того, что корректные реализации на ECMAScript не будут определять эти свойства каком-либо иным образом.