Annotated ECMAScript 5.1

‟Ex igne vita”

11 Expressions #

11.1 Primary Expressions #

Syntax

PrimaryExpression :

this
Identifier
Literal
ArrayLiteral
ObjectLiteral
( Expression )

11.1.1 The this Keyword #

The this keyword evaluates to the value of the ThisBinding of the current execution context.

11.1.2 Identifier Reference #

An Identifier is evaluated by performing Identifier Resolution as specified in 10.3.1. The result of evaluating an Identifier is always a value of type Reference.

11.1.3 Literal Reference #

A Literal is evaluated as described in 7.8.

11.1.4 Array Initialiser #

An array initialiser is an expression describing the initialisation of an Array object, written in a form of a literal. It is a list of zero or more expressions, each of which represents an array element, enclosed in square brackets. The elements need not be literals; they are evaluated each time the array initialiser is evaluated.

Array elements may be elided at the beginning, middle or end of the element list. Whenever a comma in the element list is not preceded by an AssignmentExpression (i.e., a comma at the beginning or after another comma), the missing array element contributes to the length of the Array and increases the index of subsequent elements. Elided array elements are not defined. If an element is elided at the end of an array, that element does not contribute to the length of the Array.

Syntax

ArrayLiteral :

[ Elisionopt ]
[
ElementList ]
[
ElementList , Elisionopt ]

ElementList :

Elisionopt AssignmentExpression
ElementList
, Elisionopt AssignmentExpression

Elision :

,
Elision
,

Semantics

The production ArrayLiteral : [ Elisionopt ] is evaluated as follows:

  1. Let array be the result of creating a new object as if by the expression new Array() where Array is the standard built-in constructor with that name.

  2. Let pad be the result of evaluating Elision; if not present, use the numeric value zero.

  3. Call the [[Put]] internal method of array with arguments "length", pad, and false.

  4. Return array.

The production ArrayLiteral : [ ElementList ] is evaluated as follows:

  1. Return the result of evaluating ElementList.

The production ArrayLiteral : [ ElementList , Elisionopt ] is evaluated as follows:

  1. Let array be the result of evaluating ElementList.

  2. Let pad be the result of evaluating Elision; if not present, use the numeric value zero.

  3. Let len be the result of calling the [[Get]] internal method of array with argument "length".

  4. Call the [[Put]] internal method of array with arguments "length", ToUint32(pad+len), and false.

  5. Return array.

The production ElementList : Elisionopt AssignmentExpression is evaluated as follows:

  1. Let array be the result of creating a new object as if by the expression new Array() where Array is the standard built-in constructor with that name.

  2. Let firstIndex be the result of evaluating Elision; if not present, use the numeric value zero.

  3. Let initResult be the result of evaluating AssignmentExpression.

  4. Let initValue be GetValue(initResult).

  5. Call the [[DefineOwnProperty]] internal method of array with arguments ToString(firstIndex), the Property Descriptor { [[Value]]: initValue, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.

  6. Return array.

The production ElementList : ElementList , Elisionopt AssignmentExpression is evaluated as follows:

  1. Let array be the result of evaluating ElementList.

  2. Let pad be the result of evaluating Elision; if not present, use the numeric value zero.

  3. Let initResult be the result of evaluating AssignmentExpression.

  4. Let initValue be GetValue(initResult).

  5. Let len be the result of calling the [[Get]] internal method of array with argument "length".

  6. Call the [[DefineOwnProperty]] internal method of array with arguments ToString(ToUint32((pad+len)) and the Property Descriptor { [[Value]]: initValue, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.

  7. Return array.

The production Elision : , is evaluated as follows:

  1. Return the numeric value 1.

The production Elision : Elision , is evaluated as follows:

  1. Let preceding be the result of evaluating Elision.

  2. Return preceding+1.

NOTE [[DefineOwnProperty]] is used to ensure that own properties are defined for the array even if the standard built-in Array prototype object has been modified in a manner that would preclude the creation of new own properties using [[Put]].

11.1.5 Object Initialiser #

An object initialiser is an expression describing the initialisation of an Object, written in a form resembling a literal. It is a list of zero or more pairs of property names and associated values, enclosed in curly braces. The values need not be literals; they are evaluated each time the object initialiser is evaluated.

Syntax

ObjectLiteral :

{ }
{ PropertyNameAndValueList }
{
PropertyNameAndValueList , }

PropertyNameAndValueList :

PropertyAssignment
PropertyNameAndValueList
, PropertyAssignment

PropertyAssignment :

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

PropertyName :

IdentifierName
StringLiteral
NumericLiteral

PropertySetParameterList :

Identifier

Semantics

The production ObjectLiteral : { } is evaluated as follows:

  1. Return a new object created as if by the expression new Object() where Object is the standard built-in constructor with that name.

The productions ObjectLiteral : { PropertyNameAndValueList } and
ObjectLiteral : { PropertyNameAndValueList ,} are evaluated as follows:

  1. Return the result of evaluating PropertyNameAndValueList.

The production PropertyNameAndValueList : PropertyAssignment is evaluated as follows:

  1. Let obj be the result of creating a new object as if by the expression new Object() where Object is the standard built-in constructor with that name.

  2. Let propId be the result of evaluating PropertyAssignment.

  3. Call the [[DefineOwnProperty]] internal method of obj with arguments propId.name, propId.descriptor, and false.

  4. Return obj.

The production
PropertyNameAndValueList : PropertyNameAndValueList , PropertyAssignment
is evaluated as follows:

  1. Let obj be the result of evaluating PropertyNameAndValueList.

  2. Let propId be the result of evaluating PropertyAssignment.

  3. Let previous be the result of calling the [[GetOwnProperty]] internal method of obj with argument propId.name.

  4. If previous is not undefined then throw a SyntaxError exception if any of the following conditions are true

    1. This production is contained in strict code and IsDataDescriptor(previous) is true and IsDataDescriptor(propId.descriptor) is true.

    2. IsDataDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true.

    3. IsAccessorDescriptor(previous) is true and IsDataDescriptor(propId.descriptor) is true.

    4. IsAccessorDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true and either both previous and propId.descriptor have [[Get]] fields or both previous and propId.descriptor have [[Set]] fields

  1. Call the [[DefineOwnProperty]] internal method of obj with arguments propId.name, propId.descriptor, and false.

  2. Return obj.

If the above steps would throw a SyntaxError then an implementation must treat the error as an early error (Clause 16).

The production PropertyAssignment : PropertyName : AssignmentExpression is evaluated as follows:

  1. Let propName be the result of evaluating PropertyName.

  2. Let exprValue be the result of evaluating AssignmentExpression.

  3. Let propValue be GetValue(exprValue).

  4. Let desc be the Property Descriptor{[[Value]]: propValue, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}

  5. Return Property Identifier (propName, desc).

The production PropertyAssignment : get PropertyName ( ) { FunctionBody } is evaluated as follows:

  1. Let propName be the result of evaluating PropertyName.

  2. Let closure be the result of creating a new Function object as specified in 13.2 with an empty parameter list and body specified by FunctionBody. Pass in the LexicalEnvironment of the running execution context as the Scope. Pass in true as the Strict flag if the PropertyAssignment is contained in strict code or if its FunctionBody is strict code.

  3. Let desc be the Property Descriptor{[[Get]]: closure, [[Enumerable]]: true, [[Configurable]]: true}

  4. Return Property Identifier (propName, desc).

The production PropertyAssignment : set PropertyName ( PropertySetParameterList ) { FunctionBody } is evaluated as follows:

  1. Let propName be the result of evaluating PropertyName.

  2. Let closure be the result of creating a new Function object as specified in 13.2 with parameters specified by PropertySetParameterList and body specified by FunctionBody. Pass in the LexicalEnvironment of the running execution context as the Scope. Pass in true as the Strict flag if the PropertyAssignment is contained in strict code or if its FunctionBody is strict code.

  3. Let desc be the Property Descriptor{[[Set]]: closure, [[Enumerable]]: true, [[Configurable]]: true}

  4. Return Property Identifier (propName, desc).

It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the Identifier in a PropertySetParameterList of a PropertyAssignment that is contained in strict code or if its FunctionBody is strict code.

The production PropertyName : IdentifierName is evaluated as follows:

  1. Return the String value containing the same sequence of characters as the IdentifierName.

The production PropertyName : StringLiteral is evaluated as follows:

  1. Return the SV of the StringLiteral.

The production PropertyName : NumericLiteral is evaluated as follows:

  1. Let nbr be the result of forming the value of the NumericLiteral.

  2. Return ToString(nbr).

11.1.6 The Grouping Operator #

The production PrimaryExpression : ( Expression ) is evaluated as follows:

  1. Return the result of evaluating Expression. This may be of type Reference.

NOTE This algorithm does not apply GetValue to the result of evaluating Expression. The principal motivation for this is so that operators such as delete and typeof may be applied to parenthesised expressions.

11.2 Left-Hand-Side Expressions #

Syntax

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 Property Accessors #

Properties are accessed by name, using either the dot notation:

MemberExpression . IdentifierName
CallExpression
. IdentifierName

or the bracket notation:

MemberExpression [ Expression ]
CallExpression
[ Expression ]

The dot notation is explained by the following syntactic conversion:

MemberExpression . IdentifierName

is identical in its behaviour to

MemberExpression [ <identifier-name-string> ]

and similarly

CallExpression . IdentifierName

is identical in its behaviour to

CallExpression [ <identifier-name-string> ]

where <identifier-name-string> is a string literal containing the same sequence of characters after processing of Unicode escape sequences as the IdentifierName.

The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows:

  1. Let baseReference be the result of evaluating MemberExpression.

  2. Let baseValue be GetValue(baseReference).

  3. Let propertyNameReference be the result of evaluating Expression.

  4. Let propertyNameValue be GetValue(propertyNameReference).

  5. Call CheckObjectCoercible(baseValue).

  6. Let propertyNameString be ToString(propertyNameValue).

  7. If the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let strict be false.

  8. Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.

The production CallExpression : CallExpression [ Expression ] is evaluated in exactly the same manner, except that the contained CallExpression is evaluated in step 1.

11.2.2 The new Operator #

The production NewExpression : new NewExpression is evaluated as follows:

  1. Let ref be the result of evaluating NewExpression.

  2. Let constructor be GetValue(ref).

  3. If Type(constructor) is not Object, throw a TypeError exception.

  4. If constructor does not implement the [[Construct]] internal method, throw a TypeError exception.

  5. Return the result of calling the [[Construct]] internal method on constructor, providing no arguments (that is, an empty list of arguments).

The production MemberExpression : new MemberExpression Arguments is evaluated as follows:

  1. Let ref be the result of evaluating MemberExpression.

  2. Let constructor be GetValue(ref).

  3. Let argList be the result of evaluating Arguments, producing an internal list of argument values (11.2.4).

  4. If Type(constructor) is not Object, throw a TypeError exception.

  5. If constructor does not implement the [[Construct]] internal method, throw a TypeError exception.

  6. Return the result of calling the [[Construct]] internal method on constructor, providing the list argList as the argument values.

11.2.3 Function Calls #

The production CallExpression : MemberExpression Arguments is evaluated as follows:

  1. Let ref be the result of evaluating MemberExpression.

  2. Let func be GetValue(ref).

  3. Let argList be the result of evaluating Arguments, producing an internal list of argument values (see 11.2.4).

  4. If Type(func) is not Object, throw a TypeError exception.

  5. If IsCallable(func) is false, throw a TypeError exception.

  6. If Type(ref) is Reference, then

    1. If IsPropertyReference(ref) is true, then

      1. Let thisValue be GetBase(ref).

    2. Else, the base of ref is an Environment Record

      1. Let thisValue be the result of calling the ImplicitThisValue concrete method of GetBase(ref).

  7. Else, Type(ref) is not Reference.

    1. Let thisValue be undefined.

  8. Return the result of calling the [[Call]] internal method on func, providing thisValue as the this value and providing the list argList as the argument values.

The production CallExpression : CallExpression Arguments is evaluated in exactly the same manner, except that the contained CallExpression is evaluated in step 1.

NOTE The returned result will never be of type Reference if func is a native ECMAScript object. Whether calling a host object can return a value of type Reference is implementation-dependent. If a value of type Reference is returned, it must be a non-strict Property Reference.

11.2.4 Argument Lists #

The evaluation of an argument list produces a List of values (see 8.8).

The production Arguments : ( ) is evaluated as follows:

  1. Return an empty List.

The production Arguments : ( ArgumentList ) is evaluated as follows:

  1. Return the result of evaluating ArgumentList.

The production ArgumentList : AssignmentExpression is evaluated as follows:

  1. Let ref be the result of evaluating AssignmentExpression.

  2. Let arg be GetValue(ref).

  3. Return a List whose sole item is arg.

The production ArgumentList : ArgumentList , AssignmentExpression is evaluated as follows:

  1. Let precedingArgs be the result of evaluating ArgumentList.

  2. Let ref be the result of evaluating AssignmentExpression.

  3. Let arg be GetValue(ref).

  4. Return a List whose length is one greater than the length of precedingArgs and whose items are the items of precedingArgs, in order, followed at the end by arg which is the last item of the new list.

11.2.5 Function Expressions #

The production MemberExpression : FunctionExpression is evaluated as follows:

  1. Return the result of evaluating FunctionExpression.

11.3 Postfix Expressions #

Syntax

PostfixExpression :

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

11.3.1 Postfix Increment Operator #

The production PostfixExpression : LeftHandSideExpression [no LineTerminator here] ++ is evaluated as follows:

  1. Let lhs be the result of evaluating LeftHandSideExpression.

  2. Throw a SyntaxError exception if the following conditions are all true:

  1. Let oldValue be ToNumber(GetValue(lhs)).

  2. Let newValue be the result of adding the value 1 to oldValue, using the same rules as for the + operator (see 11.6.3).

  3. Call PutValue(lhs, newValue).

  4. Return oldValue.

11.3.2 Postfix Decrement Operator #

The production PostfixExpression : LeftHandSideExpression [no LineTerminator here] -- is evaluated as follows:

  1. Let lhs be the result of evaluating LeftHandSideExpression.

  2. Throw a SyntaxError exception if the following conditions are all true:

  1. Let oldValue be ToNumber(GetValue(lhs)).

  2. Let newValue be the result of subtracting the value 1 from oldValue, using the same rules as for the - operator (11.6.3).

  3. Call PutValue(lhs, newValue).

  4. Return oldValue.

11.4 Unary Operators #

Syntax

UnaryExpression :

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

11.4.1 The delete Operator #

The production UnaryExpression : delete UnaryExpression is evaluated as follows:

  1. Let ref be the result of evaluating UnaryExpression.

  2. If Type(ref) is not Reference, return true.

  3. If IsUnresolvableReference(ref) then,

    1. If IsStrictReference(ref) is true, throw a SyntaxError exception.

    2. Else, return true.

  4. If IsPropertyReference(ref) is true, then

    1. Return the result of calling the [[Delete]] internal method on ToObject(GetBase(ref)) providing GetReferencedName(ref) and IsStrictReference(ref) as the arguments.

  5. Else, ref is a Reference to an Environment Record binding, so

    1. If IsStrictReference(ref) is true, throw a SyntaxError exception.

    2. Let bindings be GetBase(ref).

    3. Return the result of calling the DeleteBinding concrete method of bindings, providing GetReferencedName(ref) as the argument.

NOTE When a delete operator occurs within strict mode code, a SyntaxError exception is thrown if its UnaryExpression is a direct reference to a variable, function argument, or function name. In addition, if a delete operator occurs within strict mode code and the property to be deleted has the attribute { [[Configurable]]: false }, a TypeError exception is thrown.

11.4.2 The void Operator #

The production UnaryExpression : void UnaryExpression is evaluated as follows:

  1. Let expr be the result of evaluating UnaryExpression.

  2. Call GetValue(expr).

  3. Return undefined.

NOTE GetValue must be called even though its value is not used because it may have observable side-effects.

11.4.3 The typeof Operator #

The production UnaryExpression : typeof UnaryExpression is evaluated as follows:

  1. Let val be the result of evaluating UnaryExpression.

  2. If Type(val) is Reference, then

    1. If IsUnresolvableReference(val) is true, return "undefined".

    2. Let val be GetValue(val).

  3. Return a String determined by Type(val) according to Table 20.

Table 20 — typeof Operator Results

Type of val

Result

Undefined

"undefined"

Null

"object"

Boolean

"boolean"

Number

"number"

String

"string"

Object (native and does not implement [[Call]])

"object"

Object (native or host and does implement [[Call]])

"function"

Object (host and does not implement [[Call]])

Implementation-defined except may not be "undefined", "boolean", "number", or "string".

11.4.4 Prefix Increment Operator #

The production UnaryExpression : ++ UnaryExpression is evaluated as follows:

  1. Let expr be the result of evaluating UnaryExpression.

  2. Throw a SyntaxError exception if the following conditions are all true:

  1. Let oldValue be ToNumber(GetValue(expr)).

  2. Let newValue be the result of adding the value 1 to oldValue, using the same rules as for the + operator (see 11.6.3).

  3. Call PutValue(expr, newValue).

  4. Return newValue.

11.4.5 Prefix Decrement Operator #

The production UnaryExpression : -- UnaryExpression is evaluated as follows:

  1. Let expr be the result of evaluating UnaryExpression.

  2. Throw a SyntaxError exception if the following conditions are all true:

  1. Let oldValue be ToNumber(GetValue(expr)).

  2. Let newValue be the result of subtracting the value 1 from oldValue, using the same rules as for the - operator (see 11.6.3).

  3. Call PutValue(expr, newValue).

  4. Return newValue.

11.4.6 Unary + Operator #

The unary + operator converts its operand to Number type.

The production UnaryExpression : + UnaryExpression is evaluated as follows:

  1. Let expr be the result of evaluating UnaryExpression.

  2. Return ToNumber(GetValue(expr)).

11.4.7 Unary - Operator #

The unary - operator converts its operand to Number type and then negates it. Note that negating +0 produces 0, and negating 0 produces +0.

The production UnaryExpression : - UnaryExpression is evaluated as follows:

  1. Let expr be the result of evaluating UnaryExpression.

  2. Let oldValue be ToNumber(GetValue(expr)).

  3. If oldValue is NaN, return NaN.

  4. Return the result of negating oldValue; that is, compute a Number with the same magnitude but opposite sign.

11.4.8 Bitwise NOT Operator ( ~ ) #

The production UnaryExpression : ~ UnaryExpression is evaluated as follows:

  1. Let expr be the result of evaluating UnaryExpression.

  2. Let oldValue be ToInt32(GetValue(expr)).

  3. Return the result of applying bitwise complement to oldValue. The result is a signed 32-bit integer.

11.4.9 Logical NOT Operator ( ! ) #

The production UnaryExpression : ! UnaryExpression is evaluated as follows:

  1. Let expr be the result of evaluating UnaryExpression.

  2. Let oldValue be ToBoolean(GetValue(expr)).

  3. If oldValue is true, return false.

  4. Return true.

11.5 Multiplicative Operators #

Syntax

MultiplicativeExpression :

UnaryExpression
MultiplicativeExpression
* UnaryExpression
MultiplicativeExpression
/ UnaryExpression
MultiplicativeExpression
% UnaryExpression

Semantics

The production MultiplicativeExpression : MultiplicativeExpression@ UnaryExpression, where @ stands for one of the operators in the above definitions, is evaluated as follows:

  1. Let left be the result of evaluating MultiplicativeExpression.

  2. Let leftValue be GetValue(left).

  3. Let right be the result of evaluating UnaryExpression.

  4. Let rightValue be GetValue(right).

  5. Let leftNum be ToNumber(leftValue).

  6. Let rightNum be ToNumber(rightValue).

  7. Return the result of applying the specified operation (*, /, or %) to leftNum and rightNum. See the Notes below 11.5.1, 11.5.2, 11.5.3.

11.5.1 Applying the * Operator #

The * operator performs multiplication, producing the product of its operands. Multiplication is commutative. Multiplication is not always associative in ECMAScript, because of finite precision.

The result of a floating-point multiplication is governed by the rules of IEEE 754 binary double-precision arithmetic:

11.5.2 Applying the / Operator #

The / operator performs division, producing the quotient of its operands. The left operand is the dividend and the right operand is the divisor. ECMAScript does not perform integer division. The operands and result of all division operations are double-precision floating-point numbers. The result of division is determined by the specification of IEEE 754 arithmetic:

11.5.3 Applying the % Operator #

The % operator yields the remainder of its operands from an implied division; the left operand is the dividend and the right operand is the divisor.

NOTE In C and C++, the remainder operator accepts only integral operands; in ECMAScript, it also accepts floating-point operands.

The result of a floating-point remainder operation as computed by the % operator is not the same as the “remainder” operation defined by IEEE 754. The IEEE 754 “remainder” operation computes the remainder from a rounding division, not a truncating division, and so its behaviour is not analogous to that of the usual integer remainder operator. Instead the ECMAScript language defines % on floating-point operations to behave in a manner analogous to that of the Java integer remainder operator; this may be compared with the C library function fmod.

The result of an ECMAScript floating-point remainder operation is determined by the rules of IEEE arithmetic:

11.6 Additive Operators #

Syntax

AdditiveExpression :

MultiplicativeExpression
AdditiveExpression
+ MultiplicativeExpression
AdditiveExpression
- MultiplicativeExpression

11.6.1 The Addition operator ( + ) #

The addition operator either performs string concatenation or numeric addition.

The production AdditiveExpression : AdditiveExpression + MultiplicativeExpression is evaluated as follows:

  1. Let lref be the result of evaluating AdditiveExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating MultiplicativeExpression.

  4. Let rval be GetValue(rref).

  5. Let lprim be ToPrimitive(lval).

  6. Let rprim be ToPrimitive(rval).

  7. If Type(lprim) is String or Type(rprim) is String, then

    1. Return the String that is the result of concatenating ToString(lprim) followed by ToString(rprim)

  8. Return the result of applying the addition operation to ToNumber(lprim) and ToNumber(rprim). See the Note below 11.6.3.

NOTE 1 No hint is provided in the calls to ToPrimitive in steps 5 and 6. All native ECMAScript objects except Date objects handle the absence of a hint as if the hint Number were given; Date objects handle the absence of a hint as if the hint String were given. Host objects may handle the absence of a hint in some other manner.

NOTE 2 Step 7 differs from step 3 of the comparison algorithm for the relational operators (11.8.5), by using the logical-or operation instead of the logical-and operation.

11.6.2 The Subtraction Operator ( - ) #

The production AdditiveExpression : AdditiveExpression - MultiplicativeExpression is evaluated as follows:

  1. Let lref be the result of evaluating AdditiveExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating MultiplicativeExpression.

  4. Let rval be GetValue(rref).

  5. Let lnum be ToNumber(lval).

  6. Let rnum be ToNumber(rval).

  7. Return the result of applying the subtraction operation to lnum and rnum. See the note below 11.6.3.

11.6.3 Applying the Additive Operators to Numbers #

The + operator performs addition when applied to two operands of numeric type, producing the sum of the operands. The - operator performs subtraction, producing the difference of two numeric operands.

Addition is a commutative operation, but not always associative.

The result of an addition is determined using the rules of IEEE 754 binary double-precision arithmetic:

The - operator performs subtraction when applied to two operands of numeric type, producing the difference of its operands; the left operand is the minuend and the right operand is the subtrahend. Given numeric operands a and b, it is always the case that ab produces the same result as a +(–b).

11.7 Bitwise Shift Operators #

Syntax

ShiftExpression :

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

11.7.1 The Left Shift Operator ( << ) #

Performs a bitwise left shift operation on the left operand by the amount specified by the right operand.

The production ShiftExpression : ShiftExpression << AdditiveExpression is evaluated as follows:

  1. Let lref be the result of evaluating ShiftExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating AdditiveExpression.

  4. Let rval be GetValue(rref).

  5. Let lnum be ToInt32(lval).

  6. Let rnum be ToUint32(rval).

  7. Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.

  8. Return the result of left shifting lnum by shiftCount bits. The result is a signed 32-bit integer.

11.7.2 The Signed Right Shift Operator ( >> ) #

Performs a sign-filling bitwise right shift operation on the left operand by the amount specified by the right operand.

The production ShiftExpression : ShiftExpression >> AdditiveExpression is evaluated as follows:

  1. Let lref be the result of evaluating ShiftExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating AdditiveExpression.

  4. Let rval be GetValue(rref).

  5. Let lnum be ToInt32(lval).

  6. Let rnum be ToUint32(rval).

  7. Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.

  8. Return the result of performing a sign-extending right shift of lnum by shiftCount bits. The most significant bit is propagated. The result is a signed 32-bit integer.

11.7.3 The Unsigned Right Shift Operator ( >>> ) #

Performs a zero-filling bitwise right shift operation on the left operand by the amount specified by the right operand.

The production ShiftExpression : ShiftExpression >>> AdditiveExpression is evaluated as follows:

  1. Let lref be the result of evaluating ShiftExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating AdditiveExpression.

  4. Let rval be GetValue(rref).

  5. Let lnum be ToUint32(lval).

  6. Let rnum be ToUint32(rval).

  7. Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.

  8. Return the result of performing a zero-filling right shift of lnum by shiftCount bits. Vacated bits are filled with zero. The result is an unsigned 32-bit integer.

11.8 Relational Operators #

Syntax

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

NOTE The “NoIn” variants are needed to avoid confusing the in operator in a relational expression with the in operator in a for statement.

Semantics

The result of evaluating a relational operator is always of type Boolean, reflecting whether the relationship named by the operator holds between its two operands.

The RelationalExpressionNoIn productions are evaluated in the same manner as the RelationalExpression productions except that the contained RelationalExpressionNoIn is evaluated instead of the contained RelationalExpression.

11.8.1 The Less-than Operator ( < ) #

The production RelationalExpression : RelationalExpression < ShiftExpression is evaluated as follows:

  1. Let lref be the result of evaluating RelationalExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating ShiftExpression.

  4. Let rval be GetValue(rref).

  5. Let r be the result of performing abstract relational comparison lval < rval. (see 11.8.5)

  6. If r is undefined, return false. Otherwise, return r.

11.8.2 The Greater-than Operator ( > ) #

The production RelationalExpression : RelationalExpression > ShiftExpression is evaluated as follows:

  1. Let lref be the result of evaluating RelationalExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating ShiftExpression.

  4. Let rval be GetValue(rref).

  5. Let r be the result of performing abstract relational comparison rval < lval with LeftFirst equal to false. (see 11.8.5).

  6. If r is undefined, return false. Otherwise, return r.

11.8.3 The Less-than-or-equal Operator ( <= ) #

The production RelationalExpression : RelationalExpression <= ShiftExpression is evaluated as follows:

  1. Let lref be the result of evaluating RelationalExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating ShiftExpression.

  4. Let rval be GetValue(rref).

  5. Let r be the result of performing abstract relational comparison rval < lval with LeftFirst equal to false. (see 11.8.5).

  6. If r is true or undefined, return false. Otherwise, return true.

11.8.4 The Greater-than-or-equal Operator ( >= ) #

The production RelationalExpression : RelationalExpression >= ShiftExpression is evaluated as follows:

  1. Let lref be the result of evaluating RelationalExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating ShiftExpression.

  4. Let rval be GetValue(rref).

  5. Let r be the result of performing abstract relational comparison lval < rval. (see 11.8.5)

  6. If r is true or undefined, return false. Otherwise, return true.

11.8.5 The Abstract Relational Comparison Algorithm #

The comparison x < y, where x and y are values, produces true, false, or undefined (which indicates that at least one operand is NaN). In addition to x and y the algorithm takes a Boolean flag named LeftFirst as a parameter. The flag is used to control the order in which operations with potentially visible side-effects are performed upon x and y. It is necessary because ECMAScript specifies left to right evaluation of expressions. The default value of LeftFirst is true and indicates that the x parameter corresponds to an expression that occurs to the left of the y parameter’s corresponding expression. If LeftFirst is false, the reverse is the case and operations must be performed upon y before x. Such a comparison is performed as follows:

  1. If the LeftFirst flag is true, then

    1. Let px be the result of calling ToPrimitive(x, hint Number).

    2. Let py be the result of calling ToPrimitive(y, hint Number).

  2. Else the order of evaluation needs to be reversed to preserve left to right evaluation

    1. Let py be the result of calling ToPrimitive(y, hint Number).

    2. Let px be the result of calling ToPrimitive(x, hint Number).

  3. If it is not the case that both Type(px) is String and Type(py) is String, then

    1. Let nx be the result of calling ToNumber(px). Because px and py are primitive values evaluation order is not important.

    2. Let ny be the result of calling ToNumber(py).

    3. If nx is NaN, return undefined.

    4. If ny is NaN, return undefined.

    5. If nx and ny are the same Number value, return false.

    6. If nx is +0 and ny is 0, return false.

    7. If nx is 0 and ny is +0, return false.

    8. If nx is +, return false.

    9. If ny is +, return true.

    10. If ny is −∞, return false.

    11. If nx is −∞, return true.

    12. If the mathematical value of nx is less than the mathematical value of ny —note that these mathematical values are both finite and not both zero—return true. Otherwise, return false.

  4. Else, both px and py are Strings

    1. If py is a prefix of px, return false. (A String value p is a prefix of String value q if q can be the result of concatenating p and some other String r. Note that any String is a prefix of itself, because r may be the empty String.)

    2. If px is a prefix of py, return true.

    3. Let k be the smallest nonnegative integer such that the character at position k within px is different from the character at position k within py. (There must be such a k, for neither String is a prefix of the other.)

    4. Let m be the integer that is the code unit value for the character at position k within px.

    5. Let n be the integer that is the code unit value for the character at position k within py.

    6. If m < n, return true. Otherwise, return false.

NOTE 1 Step 3 differs from step 7 in the algorithm for the addition operator + (11.6.1) in using and instead of or.

NOTE 2 The comparison of Strings uses a simple lexicographic ordering on sequences of code unit values. There is no attempt to use the more complex, semantically oriented definitions of character or string equality and collating order defined in the Unicode specification. Therefore String values that are canonically equal according to the Unicode standard could test as unequal. In effect this algorithm assumes that both Strings are already in normalised form. Also, note that for strings containing supplementary characters, lexicographic ordering on sequences of UTF-16 code unit values differs from that on sequences of code point values.

11.8.6 The instanceof operator #

The production RelationalExpression: RelationalExpression instanceof ShiftExpression is evaluated as follows:

  1. Let lref be the result of evaluating RelationalExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating ShiftExpression.

  4. Let rval be GetValue(rref).

  5. If Type(rval) is not Object, throw a TypeError exception.

  6. If rval does not have a [[HasInstance]] internal method, throw a TypeError exception.

  7. Return the result of calling the [[HasInstance]] internal method of rval with argument lval.

11.8.7 The in operator #

The production RelationalExpression : RelationalExpression in ShiftExpression is evaluated as follows:

  1. Let lref be the result of evaluating RelationalExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating ShiftExpression.

  4. Let rval be GetValue(rref).

  5. If Type(rval) is not Object, throw a TypeError exception.

  6. Return the result of calling the [[HasProperty]] internal method of rval with argument ToString(lval).

11.9 Equality Operators #

Syntax

EqualityExpression :

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

EqualityExpressionNoIn :

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

Semantics

The result of evaluating an equality operator is always of type Boolean, reflecting whether the relationship named by the operator holds between its two operands.

The EqualityExpressionNoIn productions are evaluated in the same manner as the EqualityExpression productions except that the contained EqualityExpressionNoIn and RelationalExpressionNoIn are evaluated instead of the contained EqualityExpression and RelationalExpression, respectively.

11.9.1 The Equals Operator ( == ) #

The production EqualityExpression : EqualityExpression == RelationalExpression is evaluated as follows:

  1. Let lref be the result of evaluating EqualityExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating RelationalExpression.

  4. Let rval be GetValue(rref).

  5. Return the result of performing abstract equality comparison rval == lval. (see 11.9.3).

11.9.2 The Does-not-equals Operator ( != ) #

The production EqualityExpression : EqualityExpression != RelationalExpression is evaluated as follows:

  1. Let lref be the result of evaluating EqualityExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating RelationalExpression.

  4. Let rval be GetValue(rref).

  5. Let r be the result of performing abstract equality comparison rval == lval. (see 11.9.3).

  6. If r is true, return false. Otherwise, return true.

11.9.3 The Abstract Equality Comparison Algorithm #

The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:

  1. If Type(x) is the same as Type(y), then

    1. If Type(x) is Undefined, return true.

    2. If Type(x) is Null, return true.

    3. If Type(x) is Number, then

      1. If x is NaN, return false.

      2. If y is NaN, return false.

      3. If x is the same Number value as y, return true.

      4. If x is +0 and y is 0, return true.

      5. If x is 0 and y is +0, return true.

      6. Return false.

    4. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false.

    5. If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.

    6. Return true if x and y refer to the same object. Otherwise, return false.

  2. If x is null and y is undefined, return true.

  3. If x is undefined and y is null, return true.

  4. If Type(x) is Number and Type(y) is String,
    return the result of the comparison x == ToNumber(y).

  5. If Type(x) is String and Type(y) is Number,
    return the result of the comparison ToNumber(x) == y.

  6. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.

  7. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).

  8. If Type(x) is either String or Number and Type(y) is Object,
    return the result of the comparison x == ToPrimitive(y).

  9. If Type(x) is Object and Type(y) is either String or Number,
    return the result of the comparison ToPrimitive(x) == y.

  10. Return false.

NOTE 1 Given the above definition of equality:

NOTE 2 The equality operators maintain the following invariants:

NOTE 3 The equality operator is not always transitive. For example, there might be two distinct String objects, each representing the same String value; each String object would be considered equal to the String value by the == operator, but the two String objects would not be equal to each other.

NOTE 4 Comparison of Strings uses a simple equality test on sequences of code unit values. There is no attempt to use the more complex, semantically oriented definitions of character or string equality and collating order defined in the Unicode specification. Therefore Strings values that are canonically equal according to the Unicode standard could test as unequal. In effect this algorithm assumes that both Strings are already in normalised form.

11.9.4 The Strict Equals Operator ( === ) #

The production EqualityExpression : EqualityExpression === RelationalExpression is evaluated as follows:

  1. Let lref be the result of evaluating EqualityExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating RelationalExpression.

  4. Let rval be GetValue(rref).

  5. Return the result of performing the strict equality comparison rval === lval. (See 11.9.6)

11.9.5 The Strict Does-not-equal Operator ( !== ) #

The production EqualityExpression : EqualityExpression !== RelationalExpression is evaluated as follows:

  1. Let lref be the result of evaluating EqualityExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating RelationalExpression.

  4. Let rval be GetValue(rref).

  5. Let r be the result of performing strict equality comparison rval === lval. (See 11.9.6)

  6. If r is true, return false. Otherwise, return true.

11.9.6 The Strict Equality Comparison Algorithm #

The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed as follows:

  1. If Type(x) is different from Type(y), return false.

  2. If Type(x) is Undefined, return true.

  3. If Type(x) is Null, return true.

  4. If Type(x) is Number, then

    1. If x is NaN, return false.

    2. If y is NaN, return false.

    3. If x is the same Number value as y, return true.

    4. If x is +0 and y is 0, return true.

    5. If x is 0 and y is +0, return true.

    6. Return false.

  5. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise, return false.

  6. If Type(x) is Boolean, return true if x and y are both true or both false; otherwise, return false.

  7. Return true if x and y refer to the same object. Otherwise, return false.

NOTE This algorithm differs from the SameValue Algorithm (9.12) in its treatment of signed zeroes and NaNs.

11.10 Binary Bitwise Operators #

Syntax

BitwiseANDExpression :

EqualityExpression
BitwiseANDExpression
& EqualityExpression

BitwiseANDExpressionNoIn :

EqualityExpressionNoIn
BitwiseANDExpressionNoIn
& EqualityExpressionNoIn

BitwiseXORExpression :

BitwiseANDExpression
BitwiseXORExpression
^ BitwiseANDExpression

BitwiseXORExpressionNoIn :

BitwiseANDExpressionNoIn
BitwiseXORExpressionNoIn
^ BitwiseANDExpressionNoIn

BitwiseORExpression :

BitwiseXORExpression
BitwiseORExpression
| BitwiseXORExpression

BitwiseORExpressionNoIn :

BitwiseXORExpressionNoIn
BitwiseORExpressionNoIn
| BitwiseXORExpressionNoIn

Semantics

The production A : A @ B, where @ is one of the bitwise operators in the productions above, is evaluated as follows:

  1. Let lref be the result of evaluating A.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating B.

  4. Let rval be GetValue(rref).

  5. Let lnum be ToInt32(lval).

  6. Let rnum be ToInt32(rval).

  7. Return the result of applying the bitwise operator @ to lnum and rnum. The result is a signed 32 bit integer.

11.11 Binary Logical Operators #

Syntax

LogicalANDExpression :

BitwiseORExpression
LogicalANDExpression
&& BitwiseORExpression

LogicalANDExpressionNoIn :

BitwiseORExpressionNoIn
LogicalANDExpressionNoIn
&& BitwiseORExpressionNoIn

LogicalORExpression :

LogicalANDExpression
LogicalORExpression
|| LogicalANDExpression

LogicalORExpressionNoIn :

LogicalANDExpressionNoIn
LogicalORExpressionNoIn
|| LogicalANDExpressionNoIn

Semantics

The production LogicalANDExpression : LogicalANDExpression && BitwiseORExpression is evaluated as follows:

  1. Let lref be the result of evaluating LogicalANDExpression.

  2. Let lval be GetValue(lref).

  3. If ToBoolean(lval) is false, return lval.

  4. Let rref be the result of evaluating BitwiseORExpression.

  5. Return GetValue(rref).

The production LogicalORExpression : LogicalORExpression || LogicalANDExpression is evaluated as follows:

  1. Let lref be the result of evaluating LogicalORExpression.

  2. Let lval be GetValue(lref).

  3. If ToBoolean(lval) is true, return lval.

  4. Let rref be the result of evaluating LogicalANDExpression.

  5. Return GetValue(rref).

The LogicalANDExpressionNoIn and LogicalORExpressionNoIn productions are evaluated in the same manner as the LogicalANDExpression and LogicalORExpression productions except that the contained LogicalANDExpressionNoIn, BitwiseORExpressionNoIn and LogicalORExpressionNoIn are evaluated instead of the contained LogicalANDExpression, BitwiseORExpression and LogicalORExpression, respectively.

NOTE The value produced by a && or || operator is not necessarily of type Boolean. The value produced will always be the value of one of the two operand expressions.

11.12 Conditional Operator ( ? : ) #

Syntax

ConditionalExpression :

LogicalORExpression
LogicalORExpression
? AssignmentExpression : AssignmentExpression

ConditionalExpressionNoIn :

LogicalORExpressionNoIn
LogicalORExpressionNoIn
? AssignmentExpression : AssignmentExpressionNoIn

Semantics

The production ConditionalExpression : LogicalORExpression ? AssignmentExpression : AssignmentExpression is evaluated as follows:

  1. Let lref be the result of evaluating LogicalORExpression.

  2. If ToBoolean(GetValue(lref)) is true, then

    1. Let trueRef be the result of evaluating the first AssignmentExpression.

    2. Return GetValue(trueRef).

  3. Else

    1. Let falseRef be the result of evaluating the second AssignmentExpression.

    2. Return GetValue(falseRef).

The ConditionalExpressionNoIn production is evaluated in the same manner as the ConditionalExpression production except that the contained LogicalORExpressionNoIn, AssignmentExpression and AssignmentExpressionNoIn are evaluated instead of the contained LogicalORExpression, first AssignmentExpression and second AssignmentExpression, respectively.

NOTE The grammar for a ConditionalExpression in ECMAScript is a little bit different from that in C and Java, which each allow the second subexpression to be an Expression but restrict the third expression to be a ConditionalExpression. The motivation for this difference in ECMAScript is to allow an assignment expression to be governed by either arm of a conditional and to eliminate the confusing and fairly useless case of a comma expression as the centre expression.

11.13 Assignment Operators #

Syntax

AssignmentExpression :

ConditionalExpression
LeftHandSideExpression AssignmentOperator AssignmentExpression

AssignmentExpressionNoIn :

ConditionalExpressionNoIn
LeftHandSideExpression AssignmentOperator AssignmentExpressionNoIn

AssignmentOperator : one of

=

*=

/=

%=

+=

-=

<<=

>>=

>>>=

&=

^=

|=

Semantics

The AssignmentExpressionNoIn productions are evaluated in the same manner as the AssignmentExpression productions except that the contained ConditionalExpressionNoIn andAssignmentExpressionNoIn are evaluated instead of the contained ConditionalExpression and AssignmentExpression, respectively.

11.13.1 Simple Assignment ( = ) #

The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:

  1. Let lref be the result of evaluating LeftHandSideExpression.

  2. Let rref be the result of evaluating AssignmentExpression.

  3. Let rval be GetValue(rref).

  4. Throw a SyntaxError exception if the following conditions are all true:

  5. Call PutValue(lref, rval).

  6. Return rval.

NOTE When an assignment occurs within strict mode code, its LeftHandSide must not evaluate to an unresolvable reference. If it does a ReferenceError exception is thrown upon assignment. The LeftHandSide also may not be a reference to a data property with the attribute value {[[Writable]]:false}, to an accessor property with the attribute value {[[Set]]:undefined}, nor to a non-existent property of an object whose [[Extensible]] internal property has the value false. In these cases a TypeError exception is thrown.

11.13.2 Compound Assignment ( op= ) #

The production AssignmentExpression : LeftHandSideExpression@ = AssignmentExpression, where @ represents one of the operators indicated above, is evaluated as follows:

  1. Let lref be the result of evaluating LeftHandSideExpression.

  2. Let lval be GetValue(lref).

  3. Let rref be the result of evaluating AssignmentExpression.

  4. Let rval be GetValue(rref).

  5. Let r be the result of applying operator @ to lval and rval.

  6. Throw a SyntaxError exception if the following conditions are all true:

  1. Call PutValue(lref, r).

  2. Return r.

NOTE See NOTE 11.13.1.

11.14 Comma Operator ( , ) #

Syntax

Expression :

AssignmentExpression
Expression
, AssignmentExpression

ExpressionNoIn :

AssignmentExpressionNoIn
ExpressionNoIn
, AssignmentExpressionNoIn

Semantics

The production Expression : Expression , AssignmentExpression is evaluated as follows:

  1. Let lref be the result of evaluating Expression.

  2. Call GetValue(lref).

  3. Let rref be the result of evaluating AssignmentExpression.

  4. Return GetValue(rref).

The ExpressionNoIn production is evaluated in the same manner as the Expression production except that the contained ExpressionNoIn and AssignmentExpressionNoIn are evaluated instead of the contained Expression and AssignmentExpression, respectively.

NOTE GetValue must be called even though its value is not used because it may have observable side-effects.