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

Поделиться

8 Типы #

Алгоритмы, рассматриваемые в данной спецификации, манипулируют значениями, у каждого из которых есть тип, к которому он относится. В данной главе описаны все возможные типы значений. Они делятся на две категории: языковые типы language types и типы спецификации specification types.

Языковые типы соответствуют значениям, которыми непосредственно манипулирует создатель кода на языке ECMAScript. К типам спецификации относятся: Undefined, Null, Boolean, String, Number и Object.

Типы спецификации соответствуют мета-значениям, используемым в алгоритмах для описания семантики конструкций языка ECMAScript и языковых типов ECMAScript. К ним относятся типы Reference, List, Completion, Property Descriptor, Property Identifier, Lexical Environment и Environment Record. Значения типов спецификации представляют собой артефакты спецификации, которые вовсе не обязательно соответствуют каким-либо конкретным сущностям в реализации ECMAScript. Они могут использоваться для описания промежуточных результатов вычисления выражения ECMAScript, при этом такие значения не могут храниться как свойства объектов или значения переменных языка ECMAScript.

В тексте данной спецификации выражение "Type(x)" используется в качестве сокращения для фразы "тип, к которому относится x", где "тип" означает языковой тип и тип спецификации, описываемые в данной главе.

8.1 Тип Undefined #

Тип Undefined Неопределенный имеет только одно значение – undefined. Всякая переменная, которой не было присвоено значения, имеет значение undefined.

8.2 Тип Null #

Тип Null имеет только одно значение – null.

8.3 Тип Boolean #

Тип Boolean Булев тип представляет собой логическую сущность, имеющую два значения – true и false.

8.4 Тип String #

Тип String Строковый тип представляет собой множество всех конечных упорядоченных последовательностей, состоящих из 16-битовых беззнаковых целочисленных значений ("элементов") в количестве ноль или более. В целом тип String используется для представления текстовых данных в активной программе на ECMAScript, при этом каждый элемент в строке String рассматривается как значение кодовой единицы (см. Главу 6). Каждый элемент считается занимающим свою позицию в последовательности, и все позиции этих элементов пронумерованы неотрицательными целыми числами. Первый элемент (если есть) находится в позиции 0, следующий элемент (если есть) – в позиции 1, и так далее. Длина строки представляет собой количество элементов в ней (то есть, 16-битовых значений). Пустая строка имеет нулевую длину и, следовательно, не содержит ни одного элемента.

Если строка содержит реальные текстовые данные, каждый элемент считается отдельной кодовой единицей в формате UTF-16. Независимо от того, действительно ли UTF-16 является фактическим форматом хранения строки, символы в этой строке пронумерованы по их начальным позициям элементов, как если бы они были представлены именно в формате UTF-16. Все операции со строками (если явно указано иначе) интерпретируют их как недифференцированные 16-битовые беззнаковые целые. Они не обеспечивают нормализованной формы результирующей строки, и не гарантируют результатов, ориентированных на язык.

ПРИМЕЧАНИЕ Основная цель этой схемы – сделать реализацию строки как можно проще и как можно более высокоэффективной. Смысл в том, чтобы текстовые данные, поступающие в среду выполнения извне (например, вводимые пользователем, полученные при считывании текста из файла, или скачанные из сети, и т.д.), преобразовывались в соответствии с Формой нормализации Юникода "С" еще до того, как их увидит активная программа. Обычно это происходит в то же время, когда входящий текст преобразовывается из своей исходной схемы кодирования символов в формат Юникода (при этом никаких дополнительных потерь не происходит). Поскольку рекомендуется, чтобы исходный код на ECMAScript был приведен в соответствие с Формой нормализации "С", строковые литералы будут гарантированно нормализованными (если гарантированно нормализованным является исходный текст), если они не содержат управляющих последовательностей Юникода.

8.5 Тип Number #

Тип Number Числовой тип имеет ровно 18437736874454810627 (то есть, 264253+3) значений, представляющих собой 64-битовые значения с удвоенной точностью в формате IEEE 754 в соответствии со Стандартом IEEE для двоичной арифметики с плавающей точкой, за исключением того, что 9007199254740990 (то есть, 2532) индивидуальных значений "не число" по стандарту IEEE представлены в языке ECMAScript как одно специальное значение NaN. (Обратите внимание, что значение NaN получается в программе с помощью выражения NaN.) В некоторых реализациях разницу между различными значениями "не число" смог бы выявить внешний код, но такое поведение зависит от реализации. Для кода ECMAScript все значения NaN неотличимы друг от друга.

Есть еще два специальные значения – положительная Бесконечность и отрицательная Бесконечность. Для краткости эти значения также передаются поясняющими символами + и −∞ соответственно. (Обратите внимание, что эти два бесконечные числовые значения образуются с помощью выражений +Infinity (или просто Infinity) и -Infinity.)

Остальные 18437736874454810624 (то есть, 264253) значения называются конечными числами. Половина из них является положительными числами, а другая половина – отрицательными. Для каждого конечного положительного числового значения существует соответствующее отрицательное значение такой же величины.

Обратите внимание, что существует как положительный ноль, так и отрицательный ноль. Для краткости, эти значения также передаются поясняющими символами +0 и 0 соответственно. (Обратите внимание, что эти два различные нулевые числовые значения образуются с помощью выражений +0 (или просто 0) и -0.)

Остальные 18437736874454810622 (то есть, 2642532) конечные ненулевые значения бывают двух типов:

18428729675200069632 (то есть, 264254) из них являются нормализованными и имеют вид

s × m × 2e

где s равно +1 или 1, m – положительное целое число меньше чем 253, но не меньше чем 252, а e – целое число от 1074 до 971 включительно.

Остальные 9007199254740990 (то есть, 2532) значения являются денормализованными и имеют вид

s × m × 2e

где s равно +1 или 1, m – положительное целое число меньше чем 252, а e равно 1074.

Обратите внимание, что все положительные и отрицательные целые числа, значение которых по модулю не превышает 253, представимы типом Number (в действительности, целое число 0 имеет два представления: +0 и -0).

Конечное число имеет нечётную значащую часть, если оно является ненулевым числом и при этом целое число m, используемое для его выражения (в одной из двух приведенных выше форм), является нечётным. В противном случае оно имеет чётную значащую часть.

В данной спецификации фраза "значение Number для x" the Number value for x, где x представляет точную ненулевую вещественную математическую величину (которая может быть даже иррациональным числом типа π), означает значение Number, выбранное следующим образом: рассмотрим множество всех конечных значений типа Number, без 0, но с двумя дополнительными значениями, которые не представимы типом Number, а именно: 21024 (то есть, +1 × 253× 2971) и 21024 (то есть, 1 × 253× 2971). Выберем из этого множества элемент, наиболее близкий по значению к x. Если одинаково близкими являются два значения, выберем то, у которого чётная значащая часть. При этом считается, что два дополнительные значения 21024 и 21024 имеют чётные значащие части. Наконец, если было выбрано 21024, заменим его на +; если было выбрано 21024, заменим его на −∞; если был выбран +0, заменим его на 0 лишь в том случае, если x менее нуля. Если выбрано любое другое значение, его следует использовать без изменений. Результатом будет являться значение Number для x. (Эта процедура в точности соответствует поведению режима "округления до ближайшего значения" в соответствии со стандартом IEEE 754.)

Некоторые операторы ECMAScript обрабатывают только целые числа от 231 до 2311 включительно, или от 0 до 2321 включительно. Эти операторы допускают любое значение типа Number, но предварительно они приводят каждое такое значение к одному из 232 целочисленных значений. Описание операторов ToInt32 и ToUint32 содержится в пунктах 9.5 и 9.6 соответственно.

8.6 Тип Object #

Объект Object представляет собой набор свойств. Каждое свойство является либо именованным свойством данных, либо именованным свойством-аксессором, либо внутренним свойством.

Именованные (не внутренние) свойства имеют два типа доступа: get и put, обозначающие извлечение и присвоение соответственно.

8.6.1 Атрибуты свойства #

Атрибуты используются в данной спецификации для определения и описания состояния именованных свойств. Именованное свойство данных ассоциирует имя с атрибутами, перечисленными в Таблице 5.

Таблица 5. Атрибуты именованных свойств данных

Наименование

Область значений

Описание

[[Value]]

Любой тип языка ECMAScript

Значение, извлеченное посредством чтения свойства.

[[Writable]]

Boolean

Если false, то попытки кода на ECMAScript изменить атрибут [[Value]] данного свойства с помощью [[Put]] не возымеют успеха.

[[Enumerable]]

Boolean

Если true, то данное свойство будет перечислено в "for-in" (см. 12.6.4). В противном случае данное свойство не будет участвовать в перечислении.

[[Configurable]]

Boolean

Если false, то попытки удалить данное свойство, изменить его, сделав свойством-аксессором, или изменить его атрибуты (кроме [[Value]]) не возымеют успеха.

Именованное свойство-аксессор ассоциирует имя с атрибутами, перечисленными в Таблице 6.

Таблица 6. Атрибуты именованных свойство-аксессоров.

Наименование

Область значений

Описание

[[Get]]

Object или Undefined

Если значением является Object, это должен быть объект функции. Каждый раз, когда производится выполнение get-доступа некого свойства, вызывается внутренний метод функции [Call]] (8.6.2) с пустым списком аргументов для возврата значения этого свойства.

[[Set]]

Object или Undefined

Если значением является Object, это должен быть объект функции. Каждый раз, когда производится выполнение set-доступа некого свойства, вызывается внутренний метод функции [Call]] (8.6.2) со списком аргументов, содержащим единственный аргумент – присвоенное значение. Действие внутреннего метода свойства [[Set]] может (хотя и не обязательно) повлиять на значение, возвращаемое последующими вызовами во внутренний метод свойства [[Get]].

[[Enumerable]]

Boolean

Если true, данное свойство должно быть перечислено в "for-in" (см. 12.6.4). В противном случае это свойство не будет участвовать в перечислении.

[[Configurable]]

Boolean

Если false, попытки удалить данное свойство, изменить его, сделав свойством данных, или изменить его атрибуты не возымеют успеха.

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

Таблица 7. Значения атрибутов по умолчанию

Наименование атрибута

Значение по умолчанию

[[Value]]

undefined

[[Get]]

undefined

[[Set]]

undefined

[[Writable]]

false

[[Enumerable]]

false

[[Configurable]]

false

8.6.2 Внутренние свойства и методы объекта #

В данной спецификации используются различные внутренние свойства для определения семантики значений объекта. Эти внутренние свойства не являются частью языка ECMAScript, их определение даётся в данной спецификации исключительно с пояснительной целью. Реализация ECMAScript должна вести себя, как если бы она создала внутренние свойства и работала с ними в соответствии с описаниями в данной спецификации. Названия внутренних свойств заключены в двойные квадратные скобки [[ ]]. Если при использовании алгоритмом какого-либо внутреннего свойства объекта данный объект не реализовывает это внутреннее свойство, будет сгенерировано исключение TypeError.

В Таблице 8 перечислены внутренние свойства, используемые в данной спецификации, которые применимы ко всем объектам ECMAScript. В Таблице 9 перечислены внутренние свойства, используемые в данной спецификации, которые применимы только к некоторым объектам ECMAScript. В этих таблицах описано поведение свойств родных объектов ECMAScript (если для некоторых видов родных объектов ECMAScript это поведение не будет описано иначе в данном документе). Объекты среды могут поддерживать эти внутренние свойства своим поведением, зависящим от реализации, если оно согласуется с ограничениями для конкретного объекта среды, описанными в данном документе.

В столбце “Область типов значений” в этих таблицах указаны типы значений, связанные с внутренними свойствами. Названия типов означают типы, описанные в Главе 8, с последующими дополнительными названиями. Слово “любое” означает, что это значение может быть любым типом языка ECMAScript. Слово “примитивный ” означает Undefined, Null, Boolean, String или Number. SpecOp означает, что данное внутреннее свойство является внутренним методом – предоставляемой реализацией процедурой, которая описывается абстрактной спецификацией операции. После “SpecOp” приводится список описательных имен параметров. Если имя параметра в точности совпадает с именем типа, значит это имя описывает тип этого параметра. Если “SpecOp” возвращает значение, тогда после списка его параметров идет символ “>”, а затем тип возвращаемого значения.

Таблица 8. Внутренние свойства, общие для всех объектов

Внутреннее свойство

Область типов значений

Описание

[[Prototype]]

Object или Null

Прототип данного объекта.

[[Class]]

String

Строковое значение, означающее классификацию объектов, заданных спецификацией.

[[Extensible]]

Boolean

Если true, к объекту могут быть добавлены собственные свойства.

[[Get]]

SpecOp(propertyName) любое

Возвращает значение именованного свойства.

[[GetOwnProperty]]

SpecOp(propertyName)

Undefined или Property Descriptor

Возвращает Дескриптор свойства именованного собственного свойства данного объекта, или undefined (в случае отсутствия).

[[GetProperty]]

SpecOp(propertyName)

Undefined или Property Descriptor

Возвращает полностью заполненный Дескриптор свойства именованного свойства данного объекта, или undefined (в случае отсутствия).

[[Put]]

SpecOp(propertyName, любое, Boolean)

Присваивает значению второго параметра заданное именованное свойство. Обработка отказов контролируется с помощью флага.

[[CanPut]]

SpecOp(propertyName) Boolean

Возвращает булево значение, означающее возможность выполнения операции [[Put]] с именем свойства propertyName.

[[HasProperty]]

SpecOp(propertyName) Boolean

Возвращает булево значение, которое указывает, есть ли уже у данного объекта свойство с таким именем.

[[Delete]]

SpecOp(propertyName, Boolean) Boolean

Удаляет из объекта заданное именованное собственное свойство. Обработка отказов контролируется с помощью флага.

[[DefaultValue]]

SpecOp(Подсказка) примитивный

Подсказка представляет собой строку. Возвращает значение по умолчанию для данного объекта.

[[DefineOwnProperty]]

SpecOp(propertyName, PropertyDescriptor, Boolean) Boolean

Создает или изменяет именованное собственное свойство таким образом, чтобы оно имело состояние, описанное Дексриптором свойства. Обработка отказов контролируется с помощью флага.

Каждый объект, в том числе объект среды, должен реализовывать все внутренние свойства, перечисленные в Таблице 8. Однако внутренний метод [[DefaultValue]] для некоторых объектов может просто сгенерировать исключение TypeError.

Все объекты имеют внутреннее свойство [[Prototype]]. Значением этого свойства является либо null, либо объект. Это значение используется для реализации наследования. Может ли объект среды выступать в качестве свойства [[Prototype]] для родного объекта, зависит от реализации. Каждая цепочка свойств [[Prototype]] должна быть конечной длины (то есть, если начать с любого объекта и рекурсивно производить переход к внутреннему свойству [[Prototype]], то в результате должно обязательно получиться значение null). Именованные свойства данных объекта [[Prototype]] наследуются (то есть, видимы как свойства дочернего объекта) для get-доступа, но не наследуются для put-доступа, а именованные свойства-аксессоры наследуются как для get-доступа, так и для put-доступа.

Каждый объект ECMAScript имеет внутреннее свойство [[Extensible]] с булевым значением, управляющее возможностью добавления к объекту именованных свойств. Если внутреннее свойство [[Extensible]] имеет значение false, добавление дополнительных именованных свойство к объекту невозможно. Кроме того, если значение [[Extensible]] – false, то значение внутренних свойств [[Class]] и [[Prototype]] данного объекта не может быть изменено. После того как значение внутреннего свойства [[Extensible]] было установлено в false, его уже невозможно изменить на true.

ПРИМЕЧАНИЕ Данная спецификация не определяет операторов или встроенных функций языка ECMAScript, которые бы позволили программе изменить внутренние свойства [[Class]] или [[Prototype]] определенного объекта или поменять значение [[Extensible]] с false на true. Расширения языка, зависящие от конкретной реализации, которые изменяют [[Class]], [[Prototype]] или [[Extensible]], не должны нарушать инварианты, описанные в предыдущем параграфе.

Значение внутреннего свойства [[Class]] определяется в данной спецификации для каждого вида встроенного объекта. Значением внутреннего свойства [[Class]] объекта среды может быть любое строковое значение, кроме перечисленных далее: "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp" и "String". Значение внутреннего свойства [[Class]] имеет внутреннее использование для различения различных видов объектов. Обратите внимание, что данная спецификация не предоставляет программе никаких средств для доступа к этому значению, кроме как посредством Object.prototype.toString (см. 15.2.4.2).

Если не указано иначе, общие внутренние методы родных объектов ECMAScript ведут себя, как описано в пункте 8.12. Несколько отличается реализация внутреннего метода [[DefineOwnProperty]] объектов Array (см. 15.4.5.1) и реализация внутреннего метода [[GetOwnProperty]] объектов String (см. 15.5.5.2). Объекты Arguments (10.6) имеют другие реализации методов [[Get]], [[GetOwnProperty]], [[DefineOwnProperty]] и [[Delete]]. Объекты Function (15.3) имеют другую реализацию метода [[Get]].

Объекты среды могут реализовывать эти внутренние методы любым образом, если не указано иначе. Например, вполне возможно, что методы [[Get]] и [[Put]] для какого-либо конкретного объекта среды действительно извлекают и сохраняют значения свойства, но при этом метод [[HasProperty]] всегда генерирует false. Однако, если реализация не поддерживает какой-либо конкретной обработки внутренних свойств объекта среды, при попытке такой обработки будет сгенерировано исключение TypeError.

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

Внутренний метод [[DefineOwnProperty]] объекта среды не должен позволять добавлять к объекту среды новое свойство, если в коде ECMAScript внутреннее свойство [[Extensible]] этого объекта среды соблюдалось как false.

Если в коде ECMAScript внутреннее свойство [[Extensible]] этого объекта среды соблюдалось как false, оно не должно впоследствии становиться true.

Таблица 9. Внутренние свойства, определяемые только для некоторых объектов

Внутреннее свойство

Область типов значений

Описание

[[PrimitiveValue]]

примитивный

Информация о внутреннем состоянии, связанная с этим объектом. Из всех стандартных встроенных объектов ECMAScript свойство [[PrimitiveValue]] реализуют только объекты Boolean, Date, Number и String.

[[Construct]]

SpecOp(List любых) Object

Создает объект. Вызывается посредством оператора new. Аргументами в SpecOp являются аргументы, передаваемые в оператор new. Объекты, реализующие этот внутренний метод, называются конструкторами.

[[Call]]

SpecOp(любой, List любых) любой или Reference

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

[[HasInstance]]

SpecOp(любое) Boolean

Возвращает значение Boolean, которое указывает, возможно ли, что данный аргумент – это Object, который был создан данным объектом. Из всех стандартных встроенных объектов ECMAScript свойство [[HasInstance]] реализуют только объекты Function.

[[Scope]]

Lexical Environment

Лексическое окружение, определяющее окружение, в котором исполняется объект Function. Из всех стандартных встроенных объектов ECMAScript свойство [[Scope]] реализуют только объекты Function.

[[FormalParameters]]

List строк

Возможно пустой Список, содержащий строки идентификатора СпискаФормальныхПараметров функции. Из всех стандартных встроенных объектов ECMAScript свойство [[FormalParameterList]] реализуют только объекты Function.

[[Code]]

Код на ECMAScript

Код функции, написанный на ECMAScript. Из всех стандартных встроенных объектов ECMAScript свойство [[Code]] реализуют только объекты Function.

[[TargetFunction]]

Объект

Целевая функция объекта функции, созданная посредством стандартного встроенного метода Function.prototype.bind. Внутреннее свойство [[TargetFunction]] имеют только объекты ECMAScript, созданные посредством метода Function.prototype.bind.

[[BoundThis]]

любое

Предварительно связанное значение this объекта функции, созданного посредством стандартного встроенного метода Function.prototype.bind. Внутреннее свойство [[BoundThis]] имеют только объекты ECMAScript, созданные посредством метода Function.prototype.bind.

[[BoundArguments]]

List любых

Предварительно связанное значение аргументов объекта функции, созданного посредством стандартного встроенного метода Function.prototype.bind. Внутреннее свойство [[BoundArguments]] имеют только объекты ECMAScript, созданные посредством метода Function.prototype.bind.

[[Match]]

SpecOp(Строка, индекс) РезультатСличения

Производит сличение с регулярным выражением и возвращает значение РезультатаСличения (см. 15.10.2.1). Из всех стандартных встроенных объектов ECMAScript свойство [[Match]] реализуют только объекты RegExp.

[[ParameterMap]]

Object

Выстраивает соответствия между свойствами объекта аргументов (см. 10.6) и формальными параметрами связанной с ними функции. Внутреннее свойство [[ParameterMap]] имеют только те объекты ECMAScript, которые являются объектами аргументов.

8.7 Тип спецификации Reference #

Тип Reference Cсылка используется, чтобы объяснить поведение операторов delete и typeof и операторов присваивания. Например, можно сказать, что "левосторонний операнд присваивания создаёт ссылку". Поведение операторов присваивания можно также объяснить и анализом синтаксической формы левостороннего оператора. Но здесь есть одна сложность: вызовы функции могут возвращать ссылки. Правда, эта возможность применима только к объектам среды: возврат ссылки не предусмотрен ни для функций ECMAScript, определяемых данной спецификацией, ни для функций, определяемых пользователем. (Еще один довод против синтаксического анализа заключается в том, что это было бы долго и неудобно, и затрагивало бы многие части спецификации.)

Reference является предвычисленной resolved привязкой имени. Ссылка состоит из трех компонентов: значения базы base value, имени по ссылке referenced name, и флага строгой ссылки strict reference с булевым значением. Значение базы – это undefined, Object, Boolean, String, Number, или запись окружения (10.2.1). Если значение базы – undefined, это означает, что значение по ссылке не удалось вычислить. Имя по ссылке – это строка.

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

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

8.7.1 GetValue (V) #

  1. Если Тип(V) не является Reference, вернуть V.

  2. Пусть base будет результатом вызова GetBase(V).

  3. Если IsUnresolvableReference(V), то сгенерировать исключение ReferenceError.

  4. Если IsPropertyReference(V), то

    1. Если HasPrimitiveBase(V) – false, тогда пусть get будет внутренним методом [[Get]] для base, в противном случае пусть get будет специальным внутренним методом [[Get]], описанным далее.

    2. Вернуть результат вызова внутреннего метода get, используя base в качестве его значения this, и передавая как аргумент GetReferencedName(V).

  5. Иначе, base должно быть environment record.

    1. Вернуть результат вызова конкретного метода GetBindingValue (см. 10.2.1) для base, передавая в качестве аргументов GetReferencedName(V) и IsStrictReference(V).

Описанный ниже внутренний метод [[Get]] используется в GetValue, когда V является ссылкой на свойство с примитивным значением базы. Этот внутренний метод вызывается с использованием base в качестве this и свойства P в качестве аргумента. При этом производятся следующие шаги:

  1. Пусть O будет ToObject(base).

  2. Пусть desc будет результатом вызова внутреннего метода [[GetProperty]] объекта O с именем свойства P.

  3. Если descundefined, вернуть undefined.

  4. Если IsDataDescriptor(desc) – true, вернуть desc.[[Value]].

  5. В противном случае IsAccessorDescriptor(desc) должен быть true, поэтому пусть getter будет desc.[[Get]].

  6. Если getter является undefined, вернуть undefined.

  7. Вернуть результат, вызывая внутренний метод [[Call]] для getter, передавая base в качестве значения this, без аргументов.

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

8.7.2 PutValue (V, W) #

  1. Если Тип(V) не является Reference, сгенерировать исключение ReferenceError.

  2. Пусть base будет результатом вызова GetBase(V).

  3. Если IsUnresolvableReference(V), то

    1. Если IsStrictReference(V) – true, то

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

    2. Вызвать внутренний метод [[Put]] объекта global object, передавая в качестве имени свойства GetReferencedName(V), в качестве значения – W , а в качестве флага Throw false.

  4. Иначе если IsPropertyReference(V), то

    1. Если HasPrimitiveBase(V) – false, тогда пусть put будет внутренним методом [[Put]] base, в противном случае пусть put будет специальным внутренним методом [[Put]], описанным далее.

    2. Вызвать внутренний метод put, используя base в качестве this, и передавая в качестве имени свойства GetReferencedName(V), в качестве значения – W, а в качестве флага Throw IsStrictReference.

  5. Иначе, base должна быть ссылкой, база которой – environment record. Таким образом,

    1. Вызвать конкретный метод SetMutableBinding (10.2.1) для base, передавая в качестве аргументов GetReferencedName(V), W и IsStrictReference(V).

  6. Вернуть результат.

Операция PutValue использует следующий внутренний метод [[Put]], когда V является ссылкой на свойство с примитивным значением базы. Этот внутренний метод вызывается с использованием base в качестве его значения this, а его аргументами являются свойство P, значение W и булев флаг Throw. При этом производятся следующие шаги:

  1. Пусть O будет ToObject(base).

  2. Если результат вызова внутреннего метода [[CanPut]] объекта O с аргументом Pfalse, то

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

    2. Иначе вернуть результат.

  3. Пусть ownDesc будет результатом вызова внутреннего метода [[GetOwnProperty]] объекта O с аргументом P.

  4. Если IsDataDescriptor(ownDesc) – true, то

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

    2. Иначе вернуть результат.

  5. Пусть desc будет результатом вызова внутреннего метода [[GetProperty]] объекта O с аргументом P. Это может быть либо собственный или наследуемый дескриптор свойства-аксессора, либо наследуемый дескриптор свойства данных.

  6. Если IsAccessorDescriptor(desc) – true, то

    1. Пусть setter будет desc.[[Set]], который не может быть undefined.

    2. Вызвать внутренний метод [[Call]] для setter, передавая base в качестве значения this, и список аргументов, содержащий только W.

  7. Иначе, это – запрос на создание собственного свойства временного объекта O.

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

  8. Вернуть результат.

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

8.8 Тип спецификации List #

Тип List Cписок используется для описания вычисления списков аргументов (см. 11.2.4) в выражениях new, в вызовах функции, а также в других алгоритмах, в которых необходим простой список значений. Значения типа List представляют собой простые упорядоченные последовательности значений, которые могут быть любой длины.

8.9 Тип спецификации Completion #

Тип Completion Завершение используется для объяснения поведения инструкций (break, continue, return и throw), производящих нелокальную передачу управления. Значения типа Completion представляют собой триады в формате (тип, значение, цель), где тип – один из следующих: normal, break, continue, return или throw, значение – любое значение языка ECMAScript или empty, а цель – любой идентификатор ECMAScript или empty.

Термин "непредвиденное завершение" abrupt completion означает любое завершение с типом, отличным от normal.

8.10 Типы спецификации Property Descriptor и Property Identifier #

Тип Property Descriptor используется для объяснения манипуляций с атрибутами именованных свойств и для построения соответствующей модели данных. Значения типа Property Descriptor представляют собой записи, состоящие из именованных полей, где имя каждого поля является именем атрибута, а его значение является значением соответствующего атрибута, согласно п. 8.6.1. Кроме того, любое поле может присутствовать или отсутствовать.

И в зависимости от наличия или использования определенных полей, значения Property Descriptor еще делятся на дескрипторы свойств данных и дескрипторы свойств-аксессоров. Дескриптор свойств данных имеет поля с названием или [[Value]], или [[Writable]]. Дескриптор свойств-аксессоров имеет поля с названием или [[Get]], или [[Set]]. Любой дескриптор свойств может иметь поля с названием [[Enumerable]] и [[Configurable]]. Значение Property Descriptor не может быть одновременно и дескриптором свойств данных, и дескриптором свойств-аксессоров. Однако оно может одновременно являться ни тем, ни другим. Родовой дескриптор свойства (ориг. "generic property descriptor" – прим. перев.) представляет собой значение Property Descriptor, которое не является ни дескриптором свойств данных, ни дескриптором свойств-аксессоров. Полностью заполненный дескриптор свойств является либо дескриптором свойств-аксессоров, либо дескриптором свойств данных, при этом все его поля соответствуют атрибутам свойства, описанных либо в Таблице 5, либо в Таблице 6 пункта 8.6.1.

Для удобства обозначений в тексте данной спецификации может использоваться объектно-буквенный синтаксис для определения значения дескриптора свойства. Например, фраза: Property Descriptor {[[Value]]: 42, [[Writable]]: false, [[Configurable]]: true} определяет дескриптор свойств данных. Порядок имен полей не имеет значения. Поля, которые явно не указаны, считаются отсутствующими.

В тексте и алгоритмах спецификации для указания на определенное поле Property Descriptor может использоваться написание через точку. Например, если D является дескриптором свойства, то фраза D.[[Value]] является сокращенным вариантом написания фразы “поле дескриптора D с именем [[Value]]”.

Тип Property Identifier Идентификатор свойства используется для связывания имени свойства с Дескриптором свойства. Значения типа Property Identifier представляют собой пары формата (имя, дескриптор), где имя – значение String, а дескриптор – значение Property Descriptor.

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

8.10.1 IsAccessorDescriptor(Desc) #

При вызове абстрактной операции IsAccessorDescriptor Является дескриптором аксессора с дескриптором свойства Desc выполняются следующие шаги:

  1. Если Desc – undefined, вернуть false.

  2. Если отсутствуют и Desc.[[Get]], и Desc.[[Set]], вернуть false.

  3. Вернуть true.

8.10.2 IsDataDescriptor(Desc) #

При вызове абстрактной операции IsDataDescriptor Является дескриптором данных с дескриптором свойства Desc выполняются следующие шаги:

  1. Если Desc undefined, вернуть false.

  2. Если отсутствуют и Desc.[[Value]], и Desc.[[Writable]], вернуть false.

  3. Вернуть true.

8.10.3 IsGenericDescriptor(Desc) #

При вызове абстрактной операции IsGenericDescriptor с дескриптором свойства Desc выполняются следующие шаги:

  1. Если Desc undefined, вернуть false.

  2. Если и IsAccessorDescriptor(Desc) и IsDataDescriptor(Desc) – false, вернуть true.

  3. Вернуть false.

8.10.4 FromPropertyDescriptor(Desc) #

При вызове абстрактной операции FromPropertyDescriptor Из дескриптора свойства с дескриптором свойства Desc выполняются следующие шаги:

В следующем алгоритме предполагается, что Desc полностью заполненный Property Descriptor, такой, как дескриптор свойств, возвращенный методом [[GetOwnProperty]] (см. 8.12.1).

  1. Если Desc – undefined, вернуть undefined.

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

  3. Если IsDataDescriptor(Desc) – true, то

    1. Вызываем внутренний метод [[DefineOwnProperty]] объекта obj с аргументами "value", Property Descriptor {[[Value]]: Desc.[[Value]], [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.

    2. Вызываем внутренний метод [[DefineOwnProperty]] объекта obj с аргументами "writable", Property Descriptor {[[Value]]: Desc.[[Writable]], [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.

  4. Иначе, IsAccessorDescriptor(Desc) должен быть true, поэтому

    1. Вызываем внутренний метод [[DefineOwnProperty]] объекта obj с аргументами "get", Property Descriptor {[[Value]]: Desc.[[Get]], [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.

    2. Вызываем внутренний метод [[DefineOwnProperty]] объекта obj с аргументами "set", Property Descriptor {[[Value]]: Desc.[[Set]], [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.

  5. Вызываем внутренний метод [[DefineOwnProperty]] объекта obj с аргументами "enumerable", Property Descriptor {[[Value]]: Desc.[[Enumerable]], [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.

  6. Вызываем внутренний метод [[DefineOwnProperty]] объекта obj с аргументами "configurable", Property Descriptor {[[Value]]: Desc.[[Configurable]], [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.

  7. Вернуть obj.

8.10.5 ToPropertyDescriptor(Obj) #

При вызове абстрактной операции ToPropertyDescriptor В дескриптор свойства с объектом Desc выполняются следующие шаги:

  1. Если Type(Obj) – не Object, сгенерировать исключение TypeError.

  2. Пусть desc будет результатом создания нового Property Descriptor, который вначале не имеет полей.

  3. Если результат вызова внутреннего метода [[HasProperty]] объекта Obj с аргументом "enumerable" – true, то

    1. Пусть enum будет результатом вызова внутреннего метода [[Get]] объекта Obj с аргументом "enumerable".

    2. Полю [[Enumerable]] дексриптора desc присвоить ToBoolean(enum).

  4. Если результат вызова внутреннего метода [[HasProperty]] объекта Obj с аргументом "configurable" – true, то

    1. Пусть conf будет результатом вызова внутреннего метода Obj [[Get]] с аргументом configurable".

    2. Полю [[Configurable]] дескриптора desc присвоить ToBoolean(conf).

  5. Если результат вызова внутреннего метода [[HasProperty]] объекта Obj с аргументом "value" – true, то

    1. Пусть value будет результатом вызова внутреннего метода [[Get]] объекта Obj с аргументом value".

    2. Полю [[Value]] дескриптора desc присвоить value.

  6. Если результат вызова внутреннего метода [[HasProperty]] объекта Obj с аргументом "writable" – true, то

    1. Пусть writable будет результатом вызова внутреннего метода [[Get]] объекта Obj с аргументом writable".

    2. Полю [[Writable]] дескриптора desc присвоить ToBoolean(writable).

  7. Если результат вызова внутреннего метода [[HasProperty]] объекта Obj с аргументом "get" – true, то

    1. Пусть getter будет результатом вызова внутреннего метода [[Get]] объекта Obj с аргументом "get".

    2. Если IsCallable(getter) – false, и getter не является undefined, то сгенерировать исключение TypeError exception

    3. Полю desc [[Get]] присвоить getter.

  8. Если результат вызова внутреннего метода [[HasProperty]] объекта Obj с аргументом "set" – true, то

    1. Пусть setter будет результатом вызова внутреннего метода [[Get]] объекта Obj с аргументом "set".

    2. Если IsCallable(setter) – false, и setter не является undefined, то сгенерировать исключение TypeError .

    3. Полю desc [[Set]] присвоить setter.

  9. Если присутствует либо desc.[[Get]], либо desc.[[Set]], то

    1. Если присутствует либо desc.[[Value]], либо desc.[[Writable]], то сгенерировать исключение TypeError.

  10. Вернуть desc.

8.11 Типы спецификации Lexical Environment и Environment Record #

Типы Lexical Environment Лексическое окружение и Environment Record Запись окружения используются для объяснения поведения разрешения имён во вложенных функциях и блоках. Эти типы и операции с ними описаны в Главе 10.

8.12 Алгоритмы для внутренних методов объектов #

В приведенных далее описаниях алгоритмов предположим, что O – родной объект ECMAScript, P – строка, Desc – запись Property Description, а Throw – булев флаг.

8.12.1 [[GetOwnProperty]](P) #

При вызове внутреннего метода [[GetOwnProperty]] объекта O с именем свойства P выполняются следующие шаги:

  1. Если у O нет собственного свойства с именем P, вернуть undefined.

  2. Пусть D будет вновь созданным Property Descriptor без полей.

  3. Пусть X будет собственным свойством объекта O с именем P.

  4. Если X – свойство данных, то

    1. Присвоить D.[[Value]] значение атрибута [[Value]] свойства X .

    2. Присвоить D.[[Writable]] значение атрибута [[Writable]] свойства X.

  5. Если X – свойство-аксессор, то

    1. Присвоить D.[[Get]] значение атрибута [[Get]] свойства X .

    2. Присвоить D.[[Set]] значение атрибута [[Set]] свойства X .

  6. Присвоить D.[[Enumerable]] значение атрибута [[Enumerable]] свойства X .

  7. Присвоить D.[[Configurable]] значение атрибута [[Configurable]] свойства X .

  8. Вернуть D.

Если же O – объект String, он имеет более сложный внутренний метод [[GetOwnProperty]], описанный в пункте 15.5.5.2.

8.12.2 [[GetProperty]](P) #

При вызове внутреннего метода [[GetProperty]] объекта O с именем свойства P выполняются следующие шаги:

  1. Пусть prop будет результатом вызова внутреннего метода [[GetOwnProperty]] объекта O с именем свойства P.

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

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

  4. Если proto – null, вернуть undefined.

  5. Вернуть результат вызова внутреннего метода [[GetProperty]] объекта proto с аргументом P.

8.12.3 [[Get]](P) #

При вызове внутреннего метода [[Get]] объекта O с именем свойства P выполняются следующие шаги:

  1. Пусть desc будет результатом вызова внутреннего метода [[GetProperty]] объекта O с именем свойства P.

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

  3. Если IsDataDescriptor(desc) – true, вернуть desc.[[Value]].

  4. В противном случае IsAccessorDescriptor(desc) должен быть true, поэтому пусть getter будет desc.[[Get]].

  5. Если getter – undefined, вернуть undefined.

  6. Вернуть результат, вызывая внутренний метод [[Call]] для getter, передавая O в качестве значения this, и не передавая никаких аргументов.

8.12.4 [[CanPut]](P) #

При вызове внутреннего метода [[CanPut]] объекта O с именем свойства P выполняются следующие шаги:

  1. Пусть desc будет результатом вызова внутреннего метода [[GetOwnProperty]] объекта O с аргументом P.

  2. Если desc – не undefined, то

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

      1. Если desc.[[Set]] – undefined, то вернуть false.

      2. Иначе вернуть true.

    2. Иначе, desc должен быть Дескриптором данных, поэтому вернуть значение desc.[[Writable]].

  3. Пусть proto будет внутренним свойством [[Prototype]] объекта O.

  4. Если protonull, то вернуть значение внутреннего свойства [[Extensible]] объекта O.

  5. Пусть inherited будет результатом вызова внутреннего метода [[GetProperty]] объекта proto с именем свойства P.

  6. Если inheritedundefined, то вернуть значение внутреннего свойства [[Extensible]] объекта O.

  7. Если IsAccessorDescriptor(inherited) true, то

    1. Если inherited.[[Set]] – undefined, то вернуть false.

    2. Иначе вернуть true.

  8. Иначе inherited должен быть ДескприпторомДанных.

    1. Если внутреннее свойство [[Extensible]] объекта Ofalse, вернуть false.

    2. Иначе вернуть значение inherited.[[Writable]].

Объекты среды могут определять дополнительные ограничения для операций [[Put]]. По возможности, объекты среды не должны допускать операций [[Put]] в тех ситуациях, когда это определение внутреннего метода [[CanPut]] возвращает false.

8.12.5 [[Put]](P, V, Throw) #

При вызове внутреннего метода [[Put]] объекта O с именем свойства P, значением V и булевым флагом Throw выполняются следующие шаги:

  1. Если результат вызова внутреннего метода [[CanPut]] объекта O с аргументом Pfalse, то

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

    2. Иначе вернуть результат.

  2. Пусть ownDesc будет результатом вызова внутреннего метода [[GetOwnProperty]] объекта O с аргументом P.

  3. Если IsDataDescriptor(ownDesc) true, то

    1. Пусть valueDesc будет Property Descriptor {[[Value]]: V}.

    2. Вызвать внутренний метод [[DefineOwnProperty]] объекта O, передавая в качестве аргументов P, valueDesc и Throw .

    3. Вернуть результат.

  4. Пусть desc будет результатом вызова внутреннего метода [[GetProperty]] объекта O с аргументом P. Это может быть либо собственный или наследуемый дескриптор свойства-аксессора, либо наследуемый дескриптор свойства данных.

  5. Если IsAccessorDescriptor(desc) true, то

    1. Пусть setter будет desc.[[Set]], который не может быть undefined.

    2. Вызвать внутренний метод [[Call]] для setter, передавая O в качестве значения this, и передавая V в качестве единственного аргумента.

  6. Иначе, создать именованное свойство данных P объекта O следующим образом:

    1. Пусть newDesc будет Property Descriptor {[[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}.

    2. Вызвать внутренний метод [[DefineOwnProperty]] объекта O, передавая в качестве аргументов P, newDesc и Throw .

  7. Вернуть результат.

8.12.6 [[HasProperty]](P) #

При вызове внутреннего метода [[HasProperty]] объекта O с именем свойства P выполняются следующие шаги:

  1. Пусть desc будет результатом вызова внутреннего метода [[GetProperty]] объекта O с именем свойства P.

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

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

8.12.7 [[Delete]](P, Throw) #

При вызове внутреннего метода [[Put]] объекта O с именем свойства P и булевым флагом Throw выполняются следующие шаги:

  1. Пусть desc будет результатом вызова внутреннего метода [[GetOwnProperty]] объекта O с именем свойства P.

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

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

    1. Убрать из объекта О собственное свойство с именем P.

    2. Вернуть true.

  4. Иначе, если Throw, то сгенерировать исключение TypeError.

  5. Вернуть false.

8.12.8 [[DefaultValue]](подсказка) #

При вызове внутреннего метода [[DefaultValue]] объекта O с подсказкой String выполняются следующие шаги:

  1. Пусть toString будет результатом вызова внутреннего метода [[Get]] объекта O с аргументом toString".

  2. Если IsCallable(toString) true, то

    1. Пусть str будет результатом вызова внутреннего метода [[Call]] метода toString, с объектомO в качестве значения this и с пустым списком аргументов.

    2. Если strпримитивное значение, вернуть str.

  3. Пусть valueOf будет результатом вызова внутреннего метода [[Get]] объекта O с аргументом valueOf".

  4. Если IsCallable(valueOf) true, то

    1. Пусть val будет результатом вызова внутреннего метода [[Call]] метода valueOf, с O в качестве значения this и с пустым списком аргументов.

    2. Если valпримитивное значение, вернуть val.

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

При вызове внутреннего метода [[DefaultValue]] объекта O с подсказкой Number выполняются следующие шаги:

  1. Пусть valueOf будет результатом вызова внутреннего метода [[Get]] объекта O с аргументом valueOf".

  2. Если IsCallable(valueOf) true, то

    1. Пусть val будет результатом вызова внутреннего метода [[Call]] метода valueOf, с O в качестве значения this и с пустым списком аргументов.

    2. Если valпримитивное значение, вернуть val.

  3. Пусть toString будет результатом вызова внутреннего метода [[Get]] объекта O с аргументом toString".

  4. Если IsCallable(toString) true, то

    1. Пусть str будет результатом вызова внутреннего метода [[Call]] метода toString, с объектом O в качестве значения this и с пустым списком аргументов.

    2. Если strпримитивное значение, вернуть str.

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

Если внутренний метод [[DefaultValue]] объекта O вызывается без подсказки, он ведет себя так, как если бы подсказка была Number, кроме случаев, когда O – объект Date (см. 15.9.6), и в этой ситуации он ведет себя, как если бы подсказка была String.

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

8.12.9 [[DefineOwnProperty]](P, Desc, Throw) #

В приведенном ниже алгоритме термин “Отказать” (ориг. "Reject" – прим. перев.) означает “Если Throwtrue, то сгенерировать исключение TypeError, иначе вернуть false”. Этот алгоритм содержит шаги, проверяющие различны поля Desc Property Descriptor на наличие определенных значений. Проверяемые таким образом поля не обязательно должны существовать в Desc. Если поле отсутствует, его значение считается false.

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

  1. Пусть current будет результатом вызова внутреннего метода [[GetOwnProperty]] объекта O с именем свойства P.

  2. Пусть extensible будет значением внутреннего свойства [[Extensible]] объекта O.

  3. Если current undefined, а extensiblefalse, то Отказать.

  4. Если current undefined, а extensibletrue, то

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

      1. Создать собственное свойство данных с именем P объекта O, у которых значения атрибутов [[Value]], [[Writable]], [[Enumerable]] и [[Configurable]] описывает дескриптор Desc. Если значение поля атрибута Desc отсутствует, атрибуту только что созданного свойства присваивается его значение по умолчанию.

    2. Иначе Desc должен быть Дескриптором свойств-аксессоров, поэтому

      1. Создать собственное свойство-аксессор с именем P объекта O, у которых значения атрибутов [[Get]], [[Set]], [[Enumerable]] и [[Configurable]] описывает Desc. Если значение поля атрибута Desc отсутствует, атрибуту только что созданного свойства присваивается его значение по умолчанию.

    3. Вернуть true.

  5. Вернуть true, если все поля в Desc отсутствуют.

  6. Вернуть true, если все поля в Desc также встречаются в current, и значение каждого поля в Desc оказывается таким же, что и у соответствующего поля в current при сравнении с помощью алгоритма SameValue (9.12).

  7. Если поле [[Configurable]] у currentfalse, то

    1. Отказать, если поле [[Configurable]] у Desctrue.

    2. Отказать, если имеется поле [[Enumerable]] у Desc, и поля [[Enumerable]] у current и Desc являются булевыми отрицаниями друг друга.

  8. Если IsGenericDescriptor (Desc) – true, то дальнейшей проверки не требуется.

  9. Иначе, если IsDataDescriptor(current) и IsDataDescriptor(Desc) имеют различные результаты, то

    1. Отказать, если поле [[Configurable]] у currentfalse.

    2. Если IsDataDescriptor(current) – true, то

      1. Преобразовать свойство с именем P объекта O из свойства данных в свойство-аксессор. Сохранить существующие значения атрибутов [[Configurable]] и [[Enumerable]] преобразованных свойств и присвоить атрибутам остальных свойств их значения по умолчанию.

    3. Иначе

      1. Преобразовать свойство с именем P объекта O из свойства-аксессора в свойство данных. Сохранить существующие значения атрибутов [[Configurable]] и [[Enumerable]] преобразованных свойств и присвоить атрибутам остальных свойств их значения по умолчанию.

  10. Иначе, если и IsDataDescriptor(current) и IsDataDescriptor(Desc) – true, то

    1. Если поле [[Configurable]] у currentfalse, то

      1. Отказать, если поле [[Writable]] у currentfalse, и поле [[Writable]] у Desctrue.

      2. Если поле [[Writable]] у currentfalse, то

        1. Отказать, если у Desc имеется поле [[Value]] и SameValue(Desc.[[Value]], current.[[Value]]) – false.

    2. иначе, поле [[Configurable]] у currenttrue, поэтому любое изменение является допустимым.

  11. Иначе, и IsAccessorDescriptor(current), и IsAccessorDescriptor(Desc) – true, поэтому

    1. Если поле [[Configurable]] у currentfalse, то

      1. Отказать, если у Desc имеется поле [[Set]] и SameValue(Desc.[[Set]], current.[[Set]]) – false.

      2. Отказать, если у Desc имеется поле [[Get]] и SameValue(Desc.[[Get]], current.[[Get]]) – false.

  12. Для каждого имеющегося поля атрибута у Desc присвоить значению этого поля атрибут с соответствующим именем, принадлежащий свойству с именем P объекта O.

  13. Вернуть true.

Если же O – объект Array, он имеет более сложный внутренний метод [[DefineOwnProperty]], описанный в пункте 15.4.5.1.

ПРИМЕЧАНИЕ Шаг 10.b позволяет, чтобы любое поле у Desc отличалось от соответствующего поля у current, если поле [[Configurable]] у current – true. Он даже позволяет изменить [[Value]] свойства, у которого атрибут [[Writable]] – false. Это возможно, поскольку атрибут [[Configurable]] со значением true допускает эквивалентную последовательность вызовов, в которых сначала [[Writable]] присваивается true, устанавливает новое [[Value]], а затем [[Writable]] присваивается false.