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

Поделиться

11 Выражения #

11.1 Первичные выражения #

Синтаксис

PrimaryExpression :

this
Identifier
Literal
ArrayLiteral
ObjectLiteral
( Expression )

11.1.1 Ключевое слово this #

Ключевое слово this имеет значение ThisBinding текущего контекста исполнения.

11.1.2 Ссылка на идентификатор #

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

11.1.3 Ссылка на литерал #

Вычисление значения Literal Литерал производится в соответствии с описанием в пункте 7.8.

11.1.4 Инициализатор массива #

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

Элементы массива могут быть пропущены в начале, в середине или в конце списка элементов. Если перед запятой в списке элементов отсутствует AssignmentExpression Выражение присваивания – т. е., запятая находится сразу в начале списка или непосредственно перед другой запятой – то пропущенный элемент массива увеличивает длину Array и индекс последующих элементов. Определение пропущенных элементов массива не производится. Элемент, пропущенный в конце массива, не увеличивает длину объекта Array.

Синтаксис

ArrayLiteral :

[ Elisionopt]
[
ElementList]
[
ElementList , Elisionopt]

ElementList :

ElisionoptAssignmentExpression
ElementList
, ElisionoptAssignmentExpression

Elision :

,
Elision
,

Семантика

Для вычисления ArrayLiteral : [ Elisionopt] выполняются следующие шаги:

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

  2. Пусть pad будет результатом вычисления Elision Пропуск; если он отсутствует, использовать числовое значение ноль.

  3. Вызвать внутренний метод [[Put]] для array с аргументами "length", pad и false.

  4. Вернуть array.

Для вычисления ArrayLiteral : [ ElementList] выполняются следующие шаги:

  1. Вернуть результат вычисления ElementList Список элементов.

Для вычисления ArrayLiteral : [ ElementList , Elisionopt] выполняются следующие шаги:

  1. Пусть array будет результатом вычисления ElementList.

  2. Пусть pad будет результатом вычисления Elision; если он отсутствует, использовать числовое значение ноль.

  3. Пусть len будет результатом вызова внутреннего метода [[Get]] для array с аргументом "length".

  4. Вызвать внутренний метод [[Put]] для array с аргументами "length", ToUint32(pad+len) и false.

  5. Вернуть array.

Для вычисления ElementList : ElisionoptAssignmentExpression выполняются следующие шаги:

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

  2. Пусть firstIndex будет результатом вычисления Elision; если он отсутствует, использовать числовое значение ноль.

  3. Пусть initResult будет результатом вычисления AssignmentExpression.

  4. Пусть initValue будет GetValue(initResult).

  5. Вызвать внутренний метод [[DefineOwnProperty]] для array с аргументами ToString(firstIndex), Property Descriptor { [[Value]]: initValue, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.

  6. Вернуть array.

Для вычисления ElementList : ElementList , ElisionoptAssignmentExpression выполняются следующие шаги:

  1. Пусть array будет результатом вычисления ElementList.

  2. Пусть pad будет результатом вычисления Elision; если он отсутствует, использовать числовое значение ноль.

  3. Пусть initResult будет результатом вычисления AssignmentExpression.

  4. Пусть initValue будет GetValue(initResult).

  5. Пусть len будет результатом вызова внутреннего метода [[Get]] для array с аргументом "length".

  6. Вызвать внутренний метод [[DefineOwnProperty]] для array с аргументами ToString(ToUint32((pad+len)) и Property Descriptor { [[Value]]: initValue, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.

  7. Вернуть array.

Для вычисления Elision : , выполняются следующие шаги:

  1. Вернуть числовое значение 1.

Для вычисления Elision : Elision , выполняются следующие шаги:

  1. Пусть preceding будет результатом вычисления Elision.

  2. Вернуть preceding+1.

ПРИМЕЧАНИЕ Использование внутреннего метода [[DefineOwnProperty]] позволяет обеспечить определение собственных свойства для этого массива, даже если стандартный встроенный объект-прототип Array был изменен таким образом, который препятствует созданию новых собственных свойств с использованием внутреннего метода [[Put]].

11.1.5 Инициализатор объекта #

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

Синтаксис

ObjectLiteral :

{ }
{ PropertyNameAndValueList}
{
PropertyNameAndValueList, }

PropertyNameAndValueList :

PropertyAssignment
PropertyNameAndValueList
,PropertyAssignment

PropertyAssignment:

PropertyName : AssignmentExpression
get PropertyName ( ) { FunctionBody }
set PropertyName ( PropertySetParameterList ) { FunctionBody }

PropertyName :

IdentifierName
StringLiteral
NumericLiteral

PropertySetParameterList:

Identifier

Семантика

Для вычисления ObjectLiteral : {} выполняются следующие шаги:

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

Для вычисления ObjectLiteral : {PropertyNameAndValueList } и
ObjectLiteral : {PropertyNameAndValueList ,} выполняются следующие шаги:

  1. Вернуть результат вычисления PropertyNameAndValueList Список имен свойств и значений.

Для вычисления PropertyNameAndValueList : PropertyAssignment выполняются следующие шаги:

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

  2. Пусть propId будет результатом вычисления PropertyAssignment Присваивания свойства.

  3. Вызвать внутренний метод [[DefineOwnProperty]] для obj с аргументами propId.name, propId.descriptor и false.

  4. Вернуть obj.

Для вычисления
PropertyNameAndValueList : PropertyNameAndValueList , PropertyAssignment
выполняются следующие шаги:

  1. Пусть obj будет результатом вычисления PropertyNameAndValueList.

  2. Пусть propId будет результатом вычисления PropertyAssignment.

  3. Пусть previous будет результатом вызова внутреннего метода [[GetOwnProperty]] для obj с аргументом propId.name.

  4. Если previous не является undefined, то сгенерировать исключение SyntaxError, если какое-либо из перечисленных ниже условий является истинным:

    1. Это правило содержится в строгом коде, и при этом IsDataDescriptor(previous) – true и IsDataDescriptor(propId.descriptor) – true.

    2. IsDataDescriptor(previous) равно true и IsAccessorDescriptor(propId.descriptor) равно true.

    3. IsAccessorDescriptor(previous) равно true и IsDataDescriptor(propId.descriptor) равно true.

    4. IsAccessorDescriptor(previous) равно true и IsAccessorDescriptor(propId.descriptor) равно true, и при этом либо и previous и propId.descriptor имеют поля [[Get]], либо и previous и propId.descriptor имеют поля [[Set]].

  1. Вызвать внутренний метод [[DefineOwnProperty]] для obj с аргументами propId.name, propId.descriptor и false.

  2. Вернуть obj.

Если при выполнении вышеперечисленных шагов будет сгенерировано исключение SyntaxError, то реализация должна интерпретировать эту ошибку как раннюю ошибку (Глава 16).

Для вычисления PropertyAssignment : PropertyName : AssignmentExpression выполняются следующие шаги:

  1. Пусть propName будет результатом вычисления PropertyName Имя свойства.

  2. Пусть exprValue будет результатом вычисления AssignmentExpression.

  3. Пусть propValue будет GetValue(exprValue).

  4. Пусть desc будет Property Descriptor{[[Value]]: propValue, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}.

  5. Вернуть Property Identifier (propName, desc).

Для вычисления PropertyAssignment : get PropertyName ( ) { FunctionBody} выполняются следующие шаги:

  1. Пусть propName будет результатом вычисления PropertyName.

  2. Пусть closure будет результатом создания нового объекта Function в соответствии с описанием в пункте 13.2, с пустым списком параметров, при этом тело определено посредством FunctionBody. Передать LexicalEnvironment активного контекста исполнения в качестве области видимости Scope. Передать true в качестве флага Strict, если PropertyAssignment содержится в строгом коде, или если FunctionBodyстрогий код.

  3. Пусть desc будет Property Descriptor{[[Get]]: closure, [[Enumerable]]: true, [[Configurable]]: true}.

  4. Вернуть Property Identifier (propName, desc).

Для вычисления PropertyAssignment : set PropertyName ( PropertySetParameterList) {FunctionBody } выполняются следующие шаги:

  1. Пусть propName будет результатом вычисления PropertyName.

  2. Пусть closure будет результатом создания нового объекта Function в соответствии с описанием в пункте 13.2, с параметрами, заданными посредством PropertySetParameterList Список параметров набора свойств, при этом тело определено посредством FunctionBody. Передать LexicalEnvironment активного контекста исполнения в качестве области видимости Scope. Передать true в качестве флага Strict, если PropertyAssignment содержится в строгом коде, или если FunctionBodyстрогий код.

  3. Пусть desc будет Property Descriptor{[[Set]]: closure, [[Enumerable]]: true, [[Configurable]]: true}.

  4. Вернуть Property Identifier (propName, desc).

Если Identifier "eval" или Identifier "arguments" встречается как Identifier в PropertySetParameterList для PropertyAssignment, который содержится в строгом коде, или если его FunctionBodyстрогий код, то генерируется исключение SyntaxError.

Для вычисления PropertyName : IdentifierName выполняются следующие шаги:

  1. Вернуть строковое значение, содержащее такую же последовательность символов, что и IdentifierName.

Для вычисления PropertyName : StringLiteral выполняются следующие шаги:

  1. Вернуть строковое значение StringLiteral.

Для вычисления PropertyName : NumericLiteral выполняются следующие шаги:

  1. Пусть nbr будет результатом формирования значения NumericLiteral.

  2. Вернуть ToString(nbr).

11.1.6 Оператор группировки #

Для вычисления PrimaryExpression : ( Expression ) выполняются следующие шаги:

  1. Вернуть результат вычисления Expression Выражение. Он может иметь тип Reference.

ПРИМЕЧАНИЕ Этот алгоритм не применяет операцию GetValue к результату вычисления выражения. Основная причина заключается в том, чтобы к выражениям, заключенным в круглые скобки, могли применяться операторы delete и typeof.

11.2 Левосторонние выражения #

Синтаксис

MemberExpression :

PrimaryExpression
FunctionExpression
MemberExpression
[ Expression ]
MemberExpression . IdentifierName
new MemberExpression Arguments

NewExpression :

MemberExpression
new
NewExpression

CallExpression :

MemberExpression Arguments
CallExpression Arguments
CallExpression [ Expression ]
CallExpression . IdentifierName

Arguments :

( )
(
ArgumentList )

ArgumentList :

AssignmentExpression
ArgumentList
, AssignmentExpression

LeftHandSideExpression :

NewExpression
CallExpression

11.2.1 Доступ к свойствам #

Доступ к свойствам осуществляется по имени. Для этого используется либо точечная запись (точечная нотация):

MemberExpression . IdentifierName
CallExpression
. IdentifierName

либо скобочная запись:

MemberExpression [ Expression ]
CallExpression
[ Expression ]

Для объяснения точечной записи используется следующее синтаксическое преобразование:
Запись

MemberExpression . IdentifierName

по своему поведению тождественна записи

MemberExpression [ <identifier-name-string> ]

Аналогично, запись

CallExpression . IdentifierName

по своему поведению тождественна записи

CallExpression [ <identifier-name-string> ]

где <identifier-name-string> строка имени идентификатора – строковый литерал, содержащий после обработки юникодных управляющих последовательностей такую же последовательность символов, что и IdentifierName.

Для вычисления MemberExpression : MemberExpression [ Expression ] выполняются следующие шаги

  1. Пусть baseReference будет результатом вычисления MemberExpression Выражение элемента.

  2. Пусть baseValue будет GetValue(baseReference).

  3. Пусть propertyNameReference Ссылка на имя свойства будет результатом вычисления Expression.

  4. Пусть propertyNameValue Значение имени свойства будет GetValue(propertyNameReference).

  5. Вызвать CheckObjectCoercible(baseValue).

  6. Пусть propertyNameString Строка с именем свойства будет ToString(propertyNameValue).

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

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

Для вычисления CallExpression : CallExpression [ Expression ] выполняются точно такие же шаги, за исключением того, что в шаге 1 вычисляется вложенное CallExpression.

11.2.2 Оператор new #

Для вычисления NewExpression : new NewExpression выполняются следующие шаги

  1. Пусть ref будет результатом вычисления NewExpression.

  2. Пусть constructor будет GetValue(ref).

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

  4. Если constructor не реализует внутренний метод [[Construct]], сгенерировать исключение TypeError.

  5. Вернуть результат вызова внутреннего метода [[Construct]] для constructor, без передачи аргументов (то есть, с пустым списком аргументов).

Для вычисления MemberExpression : new MemberExpression Arguments выполняются следующие шаги:

  1. Пусть ref будет результатом вычисления MemberExpression.

  2. Пусть constructor будет GetValue(ref).

  3. Пусть argList будет результатом вычисления Arguments с созданием внутреннего списка значений аргументов (11.2.4).

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

  5. Если constructor не реализует внутренний метод [[Construct]], сгенерировать исключение TypeError.

  6. Вернуть результат вызова внутреннего метода [[Construct]] для constructor, передавая в качестве значений аргументов argList.

11.2.3 Вызовы функции #

Для вычисления CallExpression : MemberExpression Arguments выполняются следующие шаги:

  1. Пусть ref будет результатом вычисления MemberExpression.

  2. Пусть func будет GetValue(ref).

  3. Пусть argList будет результатом вычисления Arguments с созданием внутреннего списка значений аргументов (см. 11.2.4).

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

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

  6. Если Type(ref) – Reference, то

    1. Если IsPropertyReference(ref) – true, то

      1. Пусть thisValue будет GetBase(ref).

    2. Иначе, база для refEnvironment Record

      1. Пусть thisValue будет результатои вызова конкретного метода ImplicitThisValue для GetBase(ref).

  7. Иначе, Type(ref) не является Reference.

    1. Пусть thisValue будет undefined.

  8. Вернуть результат вызова внутреннего метода для func, передавая thisValue в качестве значения this, и передавая список argList в качестве значений аргумента.

Для вычисления CallExpression : CallExpression Arguments выполняются точно такие же шаги, за исключением того, что в шаге 1 вычисляется вложенное CallExpression.

ПРИМЕЧАНИЕ Возвращаемый результат не будет иметь тип Reference, если func представляет собой родной объект ECMAScript. Может ли вызываемый объект среды вернуть значение типа Reference, зависит от реализации. Если возвращается значение типа Reference, оно должно быть нестрогой ссылкой на свойство.

11.2.4 Списки аргументов #

В результате вычисления списка аргументов получается список значений типа List (см. 8.8).

Для вычисления Arguments : ( ) выполняются следующие шаги:

  1. Вернуть пустой список List.

Для вычисления Arguments : ( ArgumentList ) выполняются следующие шаги:

  1. Вернуть результат вычисления ArgumentList Список аргументов.

Для вычисления ArgumentList : AssignmentExpression выполняются следующие шаги:

  1. Пусть ref будет результатом вычисления AssignmentExpression.

  2. Пусть arg будет GetValue(ref).

  3. Вернуть список List с единственным элементом arg.

Для вычисления ArgumentList : ArgumentList, AssignmentExpression выполняются следующие шаги:

  1. Пусть precedingArgs будет результатом вычисления ArgumentList.

  2. Пусть ref будет результатом вычисления AssignmentExpression.

  3. Пусть arg будет GetValue(ref).

  4. Вернуть List, длина которого на одну единицу больше длины precedingArgs, элементы которого являются элементами precedingArgs по порядку, после которых находится arg, который является последним элементом нового списка.

11.2.5 Выражения функции #

Для вычисления MemberExpression : FunctionExpression выполняются следующие шаги:

  1. Вернуть результат вычисления FunctionExpression Выражение функции.

11.3 Постфиксные выражения #

Синтаксис

PostfixExpression :

LeftHandSideExpression
LeftHandSideExpression
[no LineTerminator here] ++
LeftHandSideExpression
[no LineTerminator here] --

11.3.1 Постфиксный оператор инкремента #

Для вычисления PostfixExpression : LeftHandSideExpression [no LineTerminator here] ++ выполняются следующие шаги:

  1. Пусть lhs будет результатом вычисления LeftHandSideExpression Левостороннее выражение.

  2. Сгенерировать исключение SyntaxError, если все следующие условия являются истинными:

  1. Пусть oldValue Старое значение будет ToNumber(GetValue(lhs)).

  2. Пусть newValue Новое значение будет результатом прибавления значения 1 к значению oldValue, с применением таких же правил, что и для оператора + (см. пункт. 11.6.3).

  3. Вызвать PutValue(lhs, newValue).

  4. Вернуть oldValue.

11.3.2 Постфиксный оператор декремента #

Для вычисления PostfixExpression : LeftHandSideExpression[no LineTerminator here] -- выполняются следующие шаги:

  1. Пусть lhs будет результатом вычисления LeftHandSideExpression Левостороннее выражение.

  2. Сгенерировать исключение SyntaxError, если все следующие условия являются истинными:

  1. Пусть oldValue будет ToNumber(GetValue(lhs)).

  2. Пусть newValue будет результатом вычитания значения 1 из значения oldValue, с применением таких же правил, что и для оператора - (см. пункт. 11.6.3).

  3. Вызвать PutValue(lhs, newValue).

  4. Вернуть oldValue.

11.4 Унарные операторы #

Синтаксис

UnaryExpression :

PostfixExpression
delete
UnaryExpression
void UnaryExpression
typeof UnaryExpression
++
UnaryExpression
-- UnaryExpression
+ UnaryExpression
- UnaryExpression
~ UnaryExpression
! UnaryExpression

11.4.1 Оператор delete #

Для вычисления UnaryExpression : delete UnaryExpression выполняются следующие шаги:

  1. Пусть ref будет результатом вычисления UnaryExpression Унарное выражение.

  2. Если Type(ref) не является Reference, вернуть true.

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

    1. Если IsStrictReference(ref) – true, сгенерировать исключение SyntaxError.

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

  4. Если IsPropertyReference(ref) – true, то

    1. Вернуть результат вызова внутреннего метода [[Delete]] для абстрактной операции ToObject(GetBase(ref)), передавая в качестве аргументов GetReferencedName(ref) и IsStrictReference(ref).

  5. Иначе, ref является ссылкой Reference на привязку к среде окружения Environment Record, поэтому

    1. Если IsStrictReference(ref) – true, сгенерировать исключение SyntaxError.

    2. Пусть bindings будет GetBase(ref).

    3. Вернуть результат вызова конкретного метода DeleteBinding для bindings, передавая в качестве аргумента GetReferencedName(ref).

ПРИМЕЧАНИЕ Если оператор delete встречается в рамках кода в строгом режиме, генерируется исключение SyntaxError, если его UnaryExpression является прямой ссылкой на переменную, аргумент функции или имя функции. Кроме того, исключение TypeError генерируется, если оператор delete встречается в рамках кода в строгом режиме, и при этом свойство, подлежащее удалению, имеет атрибут { [[Configurable]]: false }.

11.4.2 Оператор void #

Для вычисления UnaryExpression : void UnaryExpression выполняются следующие шаги:

  1. Пусть expr будет результатом вычисления UnaryExpression.

  2. Вызвать GetValue(expr).

  3. Вернуть undefined.

ПРИМЕЧАНИЕ Несмотря на то, что значение абстрактной операции GetValue не используется, её необходимо вызвать, поскольку она может иметь наблюдаемые побочные эффекты.

11.4.3 Оператор typeof #

Для вычисления UnaryExpression : typeof UnaryExpression выполняются следующие шаги:

  1. Пусть val будет результатом вычисления UnaryExpression.

  2. Если Type(val) – Reference, то

    1. Если IsUnresolvableReference(val) – true, вернуть "undefined".

    2. Пусть val будет GetValue(val).

  3. Вернуть строку в зависимости от типа Type(val), в соответствии с Таблицей 20.

Таблица 20. Результаты оператора typeof

Тип для val

Результат

Undefined

"undefined"

Null

"object"

Boolean

"boolean"

Number

"number"

String

"string"

Object (родной объект, не реализует [[Call]])

"object"

Object (родной объект или объект среды, реализует [[Call]])

"function"

Object (объект среды, не реализует [[Call]])

Зависит от реализации, но не может быть "undefined", "boolean", "number" или "string".

11.4.4 Префиксный оператор инкремента #

Для выполнения UnaryExpression : ++ UnaryExpression выполняются следующие шаги:

  1. Пусть expr будет результатом вычисления UnaryExpression.

  2. Сгенерировать исключение SyntaxError, если все следующие условия являются истинными:

  1. Пусть oldValue будет ToNumber(GetValue(expr)).

  2. Пусть newValue будет результатом прибавления значения 1 к значению oldValue, с применением таких же правил, что и для оператора + (см. пункт. 11.6.3).

  3. Вызвать PutValue(expr, newValue).

  4. Вернуть newValue.

11.4.5 Префиксный оператор декремента #

Для вычисления UnaryExpression : -- UnaryExpression выполняются следующие шаги:

  1. Пусть expr будет результатом вычисления UnaryExpression.

  2. Сгенерировать исключение SyntaxError, если все следующие условия являются истинными:

  1. Пусть oldValue будет ToNumber(GetValue(expr)).

  2. Пусть newValue будет результатом вычитания значения 1 из значения oldValue, с применением таких же правил, что и для оператора - (см. пункт. 11.6.3).

  3. Вызвать PutValue(expr, newValue).

  4. Вернуть newValue.

11.4.6 Унарный оператор + #

Унарный оператор + преобразует свой операнд в тип Number.

Для вычисления UnaryExpression : + UnaryExpression выполняются следующие шаги:

  1. Пусть expr будет результатом вычисления UnaryExpression.

  2. Вернуть ToNumber(GetValue(expr)).

11.4.7 Унарный оператор - #

Унарный оператор - преобразует свой операнд в тип Number, а затем выполняет операцию отрицания. Обратите внимание, что при отрицании +0 получается 0, а при отрицании 0 получается +0.

Для вычисления UnaryExpression : - UnaryExpression выполняются следующие шаги:

  1. Пусть expr будет результатом вычисления UnaryExpression.

  2. Пусть oldValue будет ToNumber(GetValue(expr)).

  3. Если oldValue равно NaN, вернуть NaN.

  4. Вернуть результат отрицания oldValue; то есть, вычислить числовое значение такой же величины по модулю, но с противоположным знаком.

11.4.8 Побитовый оператор НЕ ( ~ ) #

Для вычисления UnaryExpression : ~ UnaryExpression выполняются следующие шаги:

  1. Пусть expr будет результатом вычисления UnaryExpression.

  2. Пусть oldValue будет ToInt32(GetValue(expr)).

  3. Вернуть результат применения к oldValue побитового дополнения. Результат является знаковым 32-битовым целым.

11.4.9 Логический оператор НЕ ( ! ) #

Для вычисления UnaryExpression : ! UnaryExpression выполняются следующие шаги:

  1. Пусть expr будет результатом вычисления UnaryExpression.

  2. Пусть oldValue будет ToBoolean(GetValue(expr)).

  3. Если oldValue равно true, вернуть false.

  4. Вернуть true.

11.5 Мультипликативные операторы #

Синтаксис

MultiplicativeExpression :

UnaryExpression
MultiplicativeExpression
* UnaryExpression
MultiplicativeExpression
/ UnaryExpression
MultiplicativeExpression
% UnaryExpression

Семантика

Для вычисления MultiplicativeExpression : MultiplicativeExpression@ UnaryExpression, где @ означает один из операторов в приведенных выше определениях, выполняются следующие шаги:

  1. Пусть left будет результатом вычисления MultiplicativeExpression Мультипликативное выражение.

  2. Пусть leftValue будет GetValue(left).

  3. Пусть right будет результатом вычисления UnaryExpression.

  4. Пусть rightValue будет GetValue(right).

  5. Пусть leftNum будет ToNumber(leftValue).

  6. Пусть rightNum будет ToNumber(rightValue).

  7. Вернуть результат применения заданного оператора (*, /, or %) к leftNum или rightNum. См. примечания, приведенные далее в пунктах 11.5.1, 11.5.2, 11.5.3.

11.5.1 Применение оператора * #

Оператор * выполняет умножение, результатом которого является произведение его операндов. Умножение является коммутативным. Из-за конечной точности вычислений умножение в ECMAScript не всегда ассоциативно.

Результат произведения чисел с плавающей точкой обусловлен правилами стандарта IEEE 754 для двоичной арифметики двойной точности:

11.5.2 Применение оператора / #

Оператор / выполняет деление, результатом которого является отношение его операндов. Левый операнд является делимым, а правый – делителем. Целочисленное деление в ECMAScript не производится. Операнды и результаты всех операций деления являются числами с плавающей точкой двойной точности. Результат деления обусловлен правилами арифметики в соответствии со стандартом IEEE 754:

11.5.3 Применение оператора % #

Оператор % генерирует остаток от деления своих операндов. Левый операнд является делимым, а правый – делителем.

ПРИМЕЧАНИЕ В языках C и C++ оператор остатка принимает только целые операнды, а в языке ECMAScript он принимает и операнды с плавающей точкой.

Результат операции получения остатка для чисел с плавающей точкой, полученный посредством оператора %, отличается от операции "остатка" в соответствии с IEEE 754. В стандарте IEEE 754 операция "остатка" вычисляет остаток от деления с округлением, а не от деления с усечением – таким образом, её поведение не аналогично поведению обычного оператора получения целого остатка. В отличие от IEEE 754, язык ECMAScript определяет поведение остатка % от операций с плавающей точкой аналогичным поведению оператора получения целого остатка в языке Java. Это можно сравнить с функцией fmod в библиотеке С.

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

11.6 Аддитивные операторы #

Синтаксис

AdditiveExpression :

MultiplicativeExpression
AdditiveExpression
+ MultiplicativeExpression
AdditiveExpression
- MultiplicativeExpression

11.6.1 Оператор сложения ( + ) #

Оператор сложения производит либо конкатенацию строк, либо суммирование чисел.

Для вычисления AdditiveExpression : AdditiveExpression + MultiplicativeExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления AdditiveExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления MultiplicativeExpression.

  4. Пусть rval будет GetValue(rref).

  5. Пусть lprim будет ToPrimitive(lval).

  6. Пусть rprim будет ToPrimitive(rval).

  7. Если Type(lprim) – String или Type(rprim) – String, то

    1. Вернуть строку, которая является результатом конкатенации строки ToString(lprim) со следующей за ней строкой ToString(rprim)

  8. Вернуть результат применения операции сложения к ToNumber(lprim) и ToNumber(rprim). См. примечание ниже в пункте 11.6.3.

ПРИМЕЧАНИЕ 1 При вызовах абстрактной операции ToPrimitive в шаге 5 и 6 подсказка не предоставляется. Все родные объекты ECMAScript (кроме объектов Date) обрабатывают отсутствие подсказки, как если бы была передана подсказка Number, а объекты Date обрабатывают отсутствие подсказки, как если бы была дана подсказка String. Объекты среды могут обрабатывать отсутствие подсказки как-либо иначе.

ПРИМЕЧАНИЕ 2 Шаг 7 отличается от шага 3 сравнительного алгоритма операторов отношения (11.8.5) использованием операции логического "или" вместо операции логического "и".

11.6.2 Оператор вычитания ( - ) #

Для вычисления AdditiveExpression : AdditiveExpression - MultiplicativeExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления AdditiveExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления MultiplicativeExpression.

  4. Пусть rval будет GetValue(rref).

  5. Пусть lnum будет ToNumber(lval).

  6. Пусть rnum будет ToNumber(rval).

  7. Вернуть результат применения операции вычитания к lnum и rnum. См. примечание ниже в пункте 11.6.3.

11.6.3 Применение аддитивных операторов к объектам типа Number #

В применении к двум числовым операндам, оператор + выполняет сложение и генерирует сумму этих операндов, а оператор - выполняет вычитание и генерирует разницу двух числовых операндов.

Сложение – коммутативная операция, однако она не всегда является ассоциативной.

Результат сложения обусловлен правилами стандарта IEEE 754 для двоичной арифметики двойной точности:

В применении к двум числовым операндам, оператор - выполняет вычитание и генерирует разницу его операндов. Левый операнд – уменьшаемое, а правый – вычитаемое. Для числовых операндов a и b, результат вычитания ab всегда равен результату сложения a +(–b).

11.7 Операторы побитового сдвига #

Синтаксис

ShiftExpression :

AdditiveExpression
ShiftExpression
<< AdditiveExpression
ShiftExpression
>> AdditiveExpression
ShiftExpression
>>> AdditiveExpression

11.7.1 Оператор сдвига влево ( << ) #

Производит над левым операндом операцию побитового сдвига влево, сдвигая его на количество бит, указанное в правом операнде.

Для вычисления ShiftExpression : ShiftExpression << AdditiveExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления ShiftExpression Выражение сдвига.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления AdditiveExpression Аддитивное выражение.

  4. Пусть rval будет GetValue(rref).

  5. Пусть lnum будет ToInt32(lval).

  6. Пусть rnum будет ToUint32(rval).

  7. Пусть shiftCount будет результатом маскировки всех битов rnum, кроме пяти младших, то есть – вычислить rnum & 0x1F.

  8. Вернуть результат сдвига lnum влево на shiftCount битов. Результат является знаковым 32-битовым целым.

11.7.2 Оператор знакового сдвига вправо ( >> ) #

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

Для вычисления ShiftExpression : ShiftExpression >> AdditiveExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления ShiftExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления AdditiveExpression.

  4. Пусть rval будет GetValue(rref).

  5. Пусть lnum будет ToInt32(lval).

  6. Пусть rnum будет ToUint32(rval).

  7. Пусть shiftCount будет результатом маскировки всех битов rnum, кроме пяти младших, то есть – вычислить rnum & 0x1F.

  8. Вернуть результат сдвига вправо с добавлением знака для lnum на shiftCount битов, при этом в освободившиеся места копируется старший бит. Результат является знаковым 32-битовым целым.

11.7.3 Оператор беззнакового сдвига вправо ( >>> ) #

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

Для вычисления ShiftExpression : ShiftExpression >>> AdditiveExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления ShiftExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления AdditiveExpression.

  4. Пусть rval будет GetValue(rref).

  5. Пусть lnum будет ToUint32(lval).

  6. Пусть rnum будет ToUint32(rval).

  7. Пусть shiftCount будет результатом маскировки всех битов rnum, кроме пяти младших, то есть – вычислить rnum & 0x1F.

  8. Вернуть результат сдвига вправо с нулевой вставкой для lnum на shiftCount битов, при этом в освободившиеся места вставляется ноль. Результат является беззнаковым 32-битовым целым.

11.8 Операторы отношения #

Синтаксис

RelationalExpression :

ShiftExpression
RelationalExpression
< ShiftExpression
RelationalExpression
> ShiftExpression
RelationalExpression
<= ShiftExpression
RelationalExpression
>= ShiftExpression
RelationalExpression
instanceof ShiftExpression
RelationalExpression
in ShiftExpression

RelationalExpressionNoIn :

ShiftExpression
RelationalExpressionNoIn
< ShiftExpression
RelationalExpressionNoIn
> ShiftExpression
RelationalExpressionNoIn
<= ShiftExpression
RelationalExpressionNoIn
>= ShiftExpression
RelationalExpressionNoIn
instanceof ShiftExpression

ПРИМЕЧАНИЕ Варианты с "NoIn" необходимы для того, чтобы не перепутать оператор in в выражении отношения с оператором in в инструкции for.

Семантика

Результат вычисления оператора отношения всегда имеет тип Boolean. Он показывает, находится ли отношение, описываемое этим оператором, в пределах его двоих операндов.

Для вычисления RelationalExpressionNoIn Выражение отношения без in выполнятся точно такие же шаги, что и для вычисления RelationalExpression Выражение отношения, за исключением того, что вместо вложенного RelationalExpression вычисляется вложенное RelationalExpressionNoIn.

11.8.1 Оператор 'Меньше чем' ( < ) #

Для вычисления RelationalExpression : RelationalExpression < ShiftExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления RelationalExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления ShiftExpression.

  4. Пусть rval будет GetValue(rref).

  5. Пусть r будет результатом абстрактного сравнения отношения lval < rval – см. пункт 11.8.5.

  6. Если rundefined, вернуть false. Иначе вернуть r.

11.8.2 Оператор 'Больше чем' ( > ) #

Для вычисления RelationalExpression : RelationalExpression > ShiftExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления RelationalExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления ShiftExpression.

  4. Пусть rval будет GetValue(rref).

  5. Пусть r будет результатом абстрактного сравнения отношения rval < lval, при этом LeftFirst равно false – см. пункт 11.8.5.

  6. Если rundefined, вернуть false. Иначе вернуть r.

11.8.3 Оператор 'Меньше или равно' ( <= ) #

Для вычисления RelationalExpression : RelationalExpression <= ShiftExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления RelationalExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления ShiftExpression.

  4. Пусть rval будет GetValue(rref).

  5. Пусть r будет результатом абстрактного сравнения отношения rval < lval, при этом LeftFirst равно false – см. пункт 11.8.5.

  6. Если rtrue или undefined, вернуть false. Иначе вернуть true.

11.8.4 Оператор 'Больше или равно' #

Для вычисления RelationalExpression : RelationalExpression >= ShiftExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления RelationalExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления ShiftExpression.

  4. Пусть rval будет GetValue(rref).

  5. Пусть r будет результатом абстрактного сравнения отношения lval < rval – см. пункт 11.8.5.

  6. Если rtrue или undefined, вернуть false. Иначе вернуть true.

11.8.5 Алгоритм сравнения абстрактного отношения #

Результатом сравнения x < y, где x и y – значения, является true, false или undefined (последнее означает, что, по крайней мере, один операнд равен NaN). Кроме x и y этот алгоритм принимает в качестве параметра булев флаг LeftFirst Сначала левый. Этот флаг контролирует порядок, в соответствии с которым над x и y производятся операции с потенциально видимыми побочными эффектами. Этот флаг необходим потому, что в языке ECMAScript задан порядок вычисления выражений слева направо. Значение флага LeftFirst по умолчанию – true, которое означает, что параметр x соответствует выражению, которое находится слева от соответствующего выражения параметра y. Если значение флага LeftFirst false, то параметры меняются местами, и сначала необходимо произвести операции над y, а потом – над x. Это сравнение производится следующим образом:

  1. Если флаг LeftFirst true, то

    1. Пусть px будет результатом вызова абстрактной операции ToPrimitive(x, подсказка Number).

    2. Пусть py будет результатом вызова абстрактной операции ToPrimitive(y, подсказка Number).

  2. Иначе, необходимо поменять местами порядок вычисления, чтобы сохранить вычисление слева направо.

    1. Пусть py будет результатом вызова абстрактной операции ToPrimitive(y, подсказка Number).

    2. Пусть px будет результатом вызова абстрактной операции ToPrimitive(x, подсказка Number).

  3. Если неверно, что и Type(px) – String, и Type(py) – String, то

    1. Пусть nx будет результатом вызова ToNumber(px). Порядок вычисления неважен, поскольку px и py примитивные значения.

    2. Пусть ny будет результатом вызова ToNumber(py).

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

    4. Если ny NaN, вернуть undefined.

    5. Если nx и ny имеют одинаковое числовое значение, вернуть false.

    6. Если nx равно +0 и ny равно 0, вернуть false.

    7. Если nx равно 0 и ny равно +0, вернуть false.

    8. Если nx равно +, вернуть false.

    9. Если ny равно +, вернуть true.

    10. Если ny равно −∞, вернуть false.

    11. Если nx равно −∞, вернуть true.

    12. Если математическое значение nx меньше, чем математическое значение ny (обратите внимание, что оба эти математические значения конечны и не являются оба равными нулю), вернуть true. В противном случае вернуть false.

  4. Иначе, и px и py – строки.

    1. Если py – префикс для px, вернуть false. (Строковое значение p является префиксом строкового значения q, если q может быть результатом конкатенации p и какой-либо другой строки r. Обратите внимание, что любая строка является префиксом самой себя, поскольку r может быть пустой строкой).

    2. Если px – префикс для py, вернуть true.

    3. Пусть k будет таким наименьшим неотрицательным целым числом, чтобы символ в позиции k в пределах px отличался от символа в позиции k в пределах py. (Такое k должно иметь место, поскольку ни одна строка не является префиксом другой.)

    4. Пусть m будет целым числом, которое имеет значение кодовой единицы для символа в позиции k в пределах px.

    5. Пусть n будет целым числом, которое имеет значение кодовой единицы для символа в позиции k в пределах py.

    6. Если m < n, вернуть true. В противном случае вернуть false.

ПРИМЕЧАНИЕ 1 Шаг 3 отличается от шага 7 в алгоритме для оператора сложения + (11.6.1) тем, что в нем используется союз "и", а не "или".

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

11.8.6 Оператор instanceof #

Для вычисления RelationalExpression: RelationalExpression instanceof ShiftExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления RelationalExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления ShiftExpression.

  4. Пусть rval будет GetValue(rref).

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

  6. Если rval не имеет внутреннего метода [[HasInstance]], сгенерировать исключение TypeError.

  7. Вернуть результат вызова внутреннего метода [[HasInstance]] для rval с аргументом lval.

11.8.7 Оператор in #

Для вычисления RelationalExpression : RelationalExpression in ShiftExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления RelationalExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления ShiftExpression.

  4. Пусть rval будет GetValue(rref).

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

  6. Вернуть результат вызова внутреннего метода [[HasProperty]] для rval с аргументом ToString(lval).

11.9 Операторы равенства #

Синтаксис

EqualityExpression :

RelationalExpression
EqualityExpression
== RelationalExpression
EqualityExpression
!= RelationalExpression
EqualityExpression
=== RelationalExpression
EqualityExpression
!== RelationalExpression

EqualityExpressionNoIn :

RelationalExpressionNoIn
EqualityExpressionNoIn
== RelationalExpressionNoIn
EqualityExpressionNoIn
!= RelationalExpressionNoIn
EqualityExpressionNoIn
=== RelationalExpressionNoIn
EqualityExpressionNoIn
!== RelationalExpressionNoIn

Семантика

Результат вычисления оператора равенства всегда имеет тип Boolean. Он показывает, находится ли отношение, описываемое этим оператором, в пределах его двоих операндов.

Для вычисления EqualityExpressionNoIn Выражение равенства без in выполняются точно такие же шаги, что и для вычисления EqualityExpression Выражение равенства , за исключением того, что вместо вложенных EqualityExpression и RelationalExpression вычисляются вложенные EqualityExpressionNoIn и RelationalExpressionNoIn, соответственно.

11.9.1 Оператор 'Равно' ( == ) #

Для вычисления EqualityExpression : EqualityExpression == RelationalExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления EqualityExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления RelationalExpression.

  4. Пусть rval будет GetValue(rref).

  5. Вернуть результат сравнения абстрактного равенства rval == lval (см. пункт 11.9.3).

11.9.2 Оператор 'Не равно' ( != ) #

Для вычисления EqualityExpression : EqualityExpression != RelationalExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления EqualityExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления RelationalExpression.

  4. Пусть rval будет GetValue(rref).

  5. Пусть r будет результатом сравнения абстрактного равенства rval == lval – см. пункт 11.9.3).

  6. Если rtrue, вернуть false. Иначе вернуть true.

11.9.3 Алгоритм сравнения абстрактного равенства #

Сравнение x == y, где x и y являются значениями, возвращает true или false. Это сравнение производится следующим образом:

  1. Если Type(x) такой же, что и Type(y), то

    1. Если Type(x) – Undefined, вернуть true.

    2. Если Type(x) – Null, вернуть true.

    3. Если Type(x) – Number, то

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

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

      3. Если x имеет такое же числовое значение, что и y, вернуть true.

      4. Если x равно +0 и y равно 0, вернуть true.

      5. Если x равно 0 и y равно +0, вернуть true.

      6. Вернуть false.

    4. Если Type(x) – String, то вернуть true, если x и y имеют абсолютно одинаковую последовательность символов (одинаковой длины и с одинаковыми символами в соответствующих позициях). В противном случае вернуть false.

    5. Если Type(x) – Boolean, вернуть true, если x и y оба являются или true, или false. В противном случае вернуть false.

    6. Вернуть true, если x и y относятся к одному и тому же объекту. В противном случае вернуть false.

  2. Если x равно null и y undefined, вернуть true.

  3. Если xundefined и y null, вернуть true.

  4. Если Type(x) – Number и Type(y) – String,
    вернуть результат сравнения x == ToNumber(y).

  5. Если Type(x) – String и Type(y) – Number,
    вернуть результат сравнения ToNumber(x) == y.

  6. Если Type(x) – Boolean, вернуть результат сравнения ToNumber(x) == y.

  7. Если Type(y) – Boolean, вернуть результат сравнения x == ToNumber(y).

  8. Если Type(x) – либо String, либо Number, и Type(y) – Object,
    вернуть результат сравнения x == ToPrimitive(y).

  9. Если Type(x) – Object и Type(y) –либо String, либо Number,
    вернуть результат сравнения ToPrimitive(x) == y.

  10. Вернуть false.

ПРИМЕЧАНИЕ Принимая во внимание вышеуказанное определение равенства:

ПРИМЕЧАНИЕ 2 Операторы равенства поддерживают следующие инварианты:

ПРИМЕЧАНИЕ 3 Оператор равенства не всегда транзитивен. Например: допустим, существуют два различные объекта типа String с одинаковым строковым значением. Каждый объект типа String будет считаться равным строковому значению посредством оператора ==, но при этом эти два объекта String не будут равны друг другу.

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

11.9.4 Оператор строгого равенства ( === ) #

Для вычисления EqualityExpression : EqualityExpression === RelationalExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления EqualityExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления RelationalExpression.

  4. Пусть rval будет GetValue(rref).

  5. Вернуть результат ставнения строгого равенства rval === lval – см. пункт 11.9.6).

11.9.5 Оператор строгого неравенства ( !== ) #

Для вычисления EqualityExpression : EqualityExpression !== RelationalExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления EqualityExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления RelationalExpression.

  4. Пусть rval будет GetValue(rref).

  5. Пусть r будет результатом сравнения строгого равенства rval == lval – см. пункт 11.9.6).

  6. Если rtrue, вернуть false. Иначе вернуть true.

11.9.6 Алгоритм сравнения строгого равенства #

Сравнение x ===y, где x и y являются значениями, возвращает true или false. Это сравнение производится следующим образом:

  1. Если Тип(x) отличается от Типа(y), вернуть false.

  2. Если Type(x) – Undefined, вернуть true.

  3. Если Type(x) – Null, вернуть true.

  4. Если Type(x) – Number, то

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

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

    3. Если x имеет такое же числовое значение, что и y, вернуть true.

    4. Если x равно +0 и y равно 0, вернуть true.

    5. Если x равно 0 и y равно +0, вернуть true.

    6. Вернуть false.

  5. Если Тип(x) – String, то вернуть true, если x и y имеют абсолютно одинаковую последовательность символов (одинаковой длины и с одинаковыми символами в соответствующих позициях), иначе вернуть false.

  6. Если Type(x) – Boolean, вернуть true, если x и y оба являются или true, или false; иначе вернуть false.

  7. Вернуть true, если x и y относятся к одному и тому же объекту. В противном случае вернуть false.

ПРИМЕЧАНИЕ Этот алгоритм отличается от алгоритма SameValue (9.12) в вопросе обработки нулей со знаком и значений "не-число" (NaN).

11.10 Бинарные побитовые операторы #

Синтаксис

BitwiseANDExpression :

EqualityExpression
BitwiseANDExpression
& EqualityExpression

BitwiseANDExpressionNoIn :

EqualityExpressionNoIn
BitwiseANDExpressionNoIn
& EqualityExpressionNoIn

BitwiseXORExpression :

BitwiseANDExpression
BitwiseXORExpression
^ BitwiseANDExpression

BitwiseXORExpressionNoIn :

BitwiseANDExpressionNoIn
BitwiseXORExpressionNoIn
^ BitwiseANDExpressionNoIn

BitwiseORExpression :

BitwiseXORExpression
BitwiseORExpression
| BitwiseXORExpression

BitwiseORExpressionNoIn :

BitwiseXORExpressionNoIn
BitwiseORExpressionNoIn
| BitwiseXORExpressionNoIn

Семантика

Для вычисления A : A @ B, где @ – один из побитовых операторов в перечисленных выше правилах, выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления A.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления B.

  4. Пусть rval будет GetValue(rref).

  5. Пусть lnum будет ToInt32(lval).

  6. Пусть rnum будет ToInt32(rval).

  7. Вернуть результат применения побитового оператора @ к lnum и rnum. Результат является знаковым 32-битовым целым.

11.11 Бинарные логические операторы #

Синтаксис

LogicalANDExpression :

BitwiseORExpression
LogicalANDExpression
&& BitwiseORExpression

LogicalANDExpressionNoIn :

BitwiseORExpressionNoIn
LogicalANDExpressionNoIn
&& BitwiseORExpressionNoIn

LogicalORExpression :

LogicalANDExpression
LogicalORExpression
|| LogicalANDExpression

LogicalORExpressionNoIn :

LogicalANDExpressionNoIn
LogicalORExpressionNoIn
|| LogicalANDExpressionNoIn

Семантика

Для вычисления LogicalANDExpression : LogicalANDExpression && BitwiseORExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления LogicalANDExpression Выражение логического И.

  2. Пусть lval будет GetValue(lref).

  3. Если ToBoolean(lval) равно false, вернуть lval.

  4. Пусть rref будет результатом вычисления BitwiseORExpression Выражение побитового ИЛИ.

  5. Вернуть GetValue(rref).

Для вычисления LogicalORExpression : LogicalORExpression || LogicalANDExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления LogicalORExpression Выражение логического ИЛИ.

  2. Пусть lval будет GetValue(lref).

  3. Если ToBoolean(lval) равно true, вернуть lval.

  4. Пусть rref будет результатом вычисления LogicalANDExpression.

  5. Вернуть GetValue(rref).

Для вычисления LogicalANDExpressionNoIn Выражение логического И без in и LogicalORExpressionNoIn Выражение логического ИЛИ без in выполняются точно такие же шаги, что и для вычисления LogicalANDExpression и LogicalORExpression, за исключением того, что вместо вложенных LogicalANDExpression, BitwiseORExpression и LogicalORExpression вычисляются вложенные LogicalANDExpressionNoIn, BitwiseORExpressionNoIn Выражение побитового ИЛИ без in и LogicalORExpressionNoIn, соответственно.

ПРИМЕЧАНИЕ Значение, возвращаемое оператором && или ||, не обязательно имеет тип Boolean, при этом оно всегда будет являться значением одного из двух выражений-операндов.

11.12 Условный оператор ( ? : ) #

Синтаксис

ConditionalExpression :

LogicalORExpression
LogicalORExpression
? AssignmentExpression : AssignmentExpression

ConditionalExpressionNoIn :

LogicalORExpressionNoIn
LogicalORExpressionNoIn
? AssignmentExpression : AssignmentExpressionNoIn

Семантика

Для вычисления UnaryExpression : LogicalORExpression ? AssignmentExpression : AssignmentExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления LogicalORExpression.

  2. Если ToBoolean(GetValue(lref)) равно true, то

    1. Пусть trueRef будет результатом вычисления первого AssignmentExpression.

    2. Вернуть GetValue(trueRef).

  3. Иначе

    1. Пусть falseRef будет результатом вычисления второго AssignmentExpression.

    2. Вернуть GetValue(falseRef).

Для вычисления ConditionalExpressionNoIn Условное выражение без in выполняются точно такие же шаги, что и для вычисления ConditionalExpression Условное выражение, за исключением того, что вместо вложенных LogicalORExpression, первого AssignmentExpression и второго AssignmentExpression вычисляются вложенные LogicalORExpressionNoIn, AssignmentExpression и AssignmentExpressionNoIn, соответственно.

ПРИМЕЧАНИЕ Грамматика условных выражений в языке ECMAScript отличается от грамматики условных выражений в языках C и Java, которые оба позволяют, чтобы второе подвыражение являлось выражением (Expression), но ограничивают третье выражение, позволяя ему быть лишь условным выражением (Conditional Expression). Это отличие в языке ECMAScript объясняется тем, что ECMAScript позволяет, чтобы выражение присваивания могло управляться любым ответвлением условного выражения; это также позволяет избежать использования запятой в качестве центрального выражения, которое является довольно бесполезным и может ввести в заблуждение.

11.13 Операторы присваивания #

Синтаксис

AssignmentExpression :

ConditionalExpression
LeftHandSideExpression AssignmentOperator AssignmentExpression

AssignmentExpressionNoIn :

ConditionalExpressionNoIn
LeftHandSideExpression AssignmentOperator AssignmentExpressionNoIn

AssignmentOperator : один из

=

*=

/=

%=

+=

-=

<<=

>>=

>>>=

&=

^=

|=

Семантика

Для вычисления AssignmentExpressionNoIn Выражение присваивания без in выполняются точно такие же шаги, что и для вычисления AssignmentExpression Выражение присваивания, за исключением того, что вместо вложенных ConditionalExpression и AssignmentExpression вычисляются вложенные ConditionalExpressionNoIn и AssignmentExpressionNoIn, соответственно.

11.13.1 Простое присваивание ( = ) #

Для вычисления AssignmentExpression : LeftHandSideExpression = AssignmentExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления LeftHandSideExpression Левосторонее выражение.

  2. Пусть rref будет результатом вычисления AssignmentExpression.

  3. Пусть rval будет GetValue(rref).

  4. Сгенерировать исключение SyntaxError, если все следующие условия являются истинными:

  5. Вызвать PutValue(lref, rval).

  6. Вернуть rval.

ПРИМЕЧАНИЕ Если присваивание имеет место в рамках кода в строгом режиме, его LeftHandSide Левая сторона при вычислении не должна производить неразрешённую ссылку. Если это происходит, то при таком присваивании генерируется исключение ReferenceError. Кроме того, LeftHandSide не может быть ссылкой на свойство данных со значением атрибута {[[Writable]]:false}, на свойство аксессоров со значением атрибута {[[Set]]:undefined}, а также на несуществующее свойство объекта, у которого внутреннее свойство [[Extensible]] имеет значение  false. В этих случаях генерируется исключение TypeError.

11.13.2 Составное присваивание ( op= ) #

Для вычисления AssignmentExpression : LeftHandSideExpression@ = AssignmentExpression, где @ означает один из перечисленных выше операторов, выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления LeftHandSideExpression.

  2. Пусть lval будет GetValue(lref).

  3. Пусть rref будет результатом вычисления AssignmentExpression.

  4. Пусть rval будет GetValue(rref).

  5. Пусть r будет результатом применения оператора @ к lval и rval.

  6. Сгенерировать исключение SyntaxError, если все следующие условия являются истинными:

  1. Вызвать PutValue(lref, r).

  2. Вернуть r.

ПРИМЕЧАНИЕ См. Примечание к пункту 11.13.1.

11.14 Оператор 'Запятая' ( , ) #

Синтаксис

Expression :

AssignmentExpression
Expression
, AssignmentExpression

ExpressionNoIn :

AssignmentExpressionNoIn
ExpressionNoIn
, AssignmentExpressionNoIn

Семантика

Для вычисления UnaryExpression : Expression , AssignmentExpression выполняются следующие шаги:

  1. Пусть lref будет результатом вычисления Expression.

  2. Вызвать GetValue(lref).

  3. Пусть rref будет результатом вычисления AssignmentExpression.

  4. Вернуть GetValue(rref).

Для вычисления ExpressionNoIn выполняются точно такие же шаги, что и для вычисления Expression, за исключением того, что вместо вложенных Expression и AssignmentExpression вычисляются вложенные ExpressionNoIn и AssignmentExpressionNoIn, соответственно.

ПРИМЕЧАНИЕ Несмотря на то, что значение абстрактной операции GetValue не используется, её необходимо вызвать, поскольку она может иметь наблюдаемые побочные эффекты.