According to Ecma-262, prefix increment and decrement operators are defined as:
UpdateExpression :
LeftHandSideExpression ++
LeftHandSideExpression ‐‐
++ UnaryExpression
‐‐ UnaryExpression
This is surprising, both that the postfix and prefix operators are defined in the same rule, and that it's ++ UnaryExpression when surely a unary expression in general is not actually a valid argument for the update operators.
It would seem cleaner and more logical to define the prefix increment and decrement operators in UnaryExpression itself, along with the other prefix operators, and other C syntax languages do this, e.g. the C standard section 6.5.3 defines unary-expression to include the prefix update operators along with the others.
Why does JavaScript define these operators the way it does?
Why does JavaScript define these operators the way it does?
It's mostly historical, as so many other oddities in the spec.
It would seem cleaner and more logical to define the prefix increment and decrement operators in UnaryExpression itself, along with the other prefix operators, and other C syntax languages do this
In fact, that's how it was defined for many years, in ES5.1 and ES6. It's simple, and has one syntactic production per precedence level (PostfixExpression being the next-tighter one), and was probably directly inherited from the C or Java grammar when JS was conceived.
Surely a unary expression in general is not actually a valid argument for the update operators
In C, -- -- x is actually valid, so that's why the prefix increment and decrement operator expressions contain another UnaryExpression. Of course, it would throw an exception when trying to evaluate the expression, but parsing it would work fine in ES5.
ES6 then added the concept of early errors, and increment and decrement operations now required a valid assignment target expression upon parsing. This was not encoded in the syntactical productions though.
It is surprising that the postfix and prefix operators are defined in the same rule
This definition is new in ES7. It changed with this commit that introduced the exponentiation operator, where the PostfixExpression was renamed to UpdateExpression and the prefix operators were moved into the rule. Some change like that was necessary because the ** operator allows an update expression, but not a UnaryExpression as its first argument (because unary minus, as in -x ** 3, was deemed too ambiguous).
Related
According to my tests it is always left-to-right
>> console.log( console.log(1), console.log(2) );
1
2
undefined undefined
but I can't find the relevant section confirming this in the ECMAScript standard.
All the operators in JavaScript evaluate their operands left-to-right, including the function call operator. First the function to call is evaluated then the actual parameters in left-to-right order.
Section 11.2.3 is the relevant spec section.
11.2.3 Function Calls
...
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).
...
and you can see that the ArgumentList production is left-recursive
11.2.4 Argument lists
...
The production ArgumentList : ArgumentList , AssignmentExpression is evaluated as follows
and ArgumentList is evaluated before AssignmentExpression in the following verbiage..
Under EcmaScript 3 some of the comparison operators (<, <=, >, >=) evaluated right to left since a<=b was defined in terms of !(b<a), but that was widely recognized as a spec error, major interpreters did not implement it that way, and it was fixed in EcmaScript 5.
From the language spec:
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:
It's defined here:
The production ArgumentList : ArgumentList , AssignmentExpression is
evaluated as follows:
Let precedingArgs be the result of evaluating ArgumentList.
Let ref be the result of evaluating AssignmentExpression.
Let arg be GetValue(ref).
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.
Read here: http://es5.github.com/#x11.2.4
When a function is invoked, the passed-in arguments are evaluated from left to right.
For historical interest, also see section 4.2 Evaluation Order of JavaScript 1.1 Language Specification (Brendan Eich, C. Rand Mckinney, 11/18/96).
In a function or constructor call, one or more argument expressions
may appear within the parentheses, separated by commas. Each argument
expression is fully evaluated before any part of any argument
expression to its right is evaluated.
By mistake, I wrote:
++number++;
and got this:
Uncaught ReferenceError: Invalid left-hand side expression in prefix operation
Why? I would except this to to first increment number by one and then increment number by one again.
In JavaScript, ++ is both the prefix and postfix increment operator. The postfix operator has higher precedence, and so when we apply precedence, your expression becomes:
++(number++);
The result of number++ is a value, not a variable reference, and so it cannot be the operand of the prefix increment operator, for the same reason ++42 is invalid — there's nowhere to write the result back to.
Why does it call it the "left-hand side expression" when it's to the right of the operator? You'd have to look at the V8 source code (I can tell from the text of the error you're doing this on V8, probably Chrome). I can speculate that it's because many operators accept two operands (left and right), and that they just call the only operand to unary operators like ++ the "left-hand" by default. But that's speculation.
I was reading the EcmaScript6 specifications and in the Arithemetic operator section ( http://www.ecma-international.org/ecma-262/5.1/#sec-11.6.1 ) its mentioned like this
AdditiveExpression :
MultiplicativeExpression
AdditiveExpression + MultiplicativeExpression
AdditiveExpression - MultiplicativeExpression
What does this mean ?
An expression of multiplication or division.
See Section 11.5
From MDN article on Expressions and operators:
An expression is any valid unit of code that resolves to a value.
So in this case a MultiplicativeExpression is any unit of code that results in multiplication. Most commonly it involves the * operator.
You can read the Annotated EcmaScript as it contains some helpful links on top of the spec.
It means that the ECMA specification is written in Martian. Or by Martians. Or for Martians. I've never been too sure, exactly.
Err, but more helpfully, section 11.6.1 explains how the "addition operator" (what we primitive humans usually call the plus sign or just "+" or "+/-") should treat the result of statements of addition, subtraction, multiplication, division, modulus division, and even string concatenation.
In the header you quote, the writers are calling attention to the various statement types they are trying to define, which is both the simple and more complex case of multiple statements that must be combined (as with the last two lines).
Later in the section it defines how 'hinting' should be handled, in what cases the script should treat variables as numbers instead of strings, etc.
It's just a really esoteric way to put it.
According to my tests it is always left-to-right
>> console.log( console.log(1), console.log(2) );
1
2
undefined undefined
but I can't find the relevant section confirming this in the ECMAScript standard.
All the operators in JavaScript evaluate their operands left-to-right, including the function call operator. First the function to call is evaluated then the actual parameters in left-to-right order.
Section 11.2.3 is the relevant spec section.
11.2.3 Function Calls
...
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).
...
and you can see that the ArgumentList production is left-recursive
11.2.4 Argument lists
...
The production ArgumentList : ArgumentList , AssignmentExpression is evaluated as follows
and ArgumentList is evaluated before AssignmentExpression in the following verbiage..
Under EcmaScript 3 some of the comparison operators (<, <=, >, >=) evaluated right to left since a<=b was defined in terms of !(b<a), but that was widely recognized as a spec error, major interpreters did not implement it that way, and it was fixed in EcmaScript 5.
From the language spec:
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:
It's defined here:
The production ArgumentList : ArgumentList , AssignmentExpression is
evaluated as follows:
Let precedingArgs be the result of evaluating ArgumentList.
Let ref be the result of evaluating AssignmentExpression.
Let arg be GetValue(ref).
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.
Read here: http://es5.github.com/#x11.2.4
When a function is invoked, the passed-in arguments are evaluated from left to right.
For historical interest, also see section 4.2 Evaluation Order of JavaScript 1.1 Language Specification (Brendan Eich, C. Rand Mckinney, 11/18/96).
In a function or constructor call, one or more argument expressions
may appear within the parentheses, separated by commas. Each argument
expression is fully evaluated before any part of any argument
expression to its right is evaluated.
Just curious. I did a program in C, with quite an amount of bitwise operations for a variable which defines access controls for a page. I wanna be able to do the same in Javascript only. How can i accomplish this ordeal?
Any help in bit-tweaking in Javascript will help. Remember no costly functions allowed.
JavaScript has the usual assortment of bitwise operators, |, &, ~, etc.; details in the specification.
The following sections will be particularly useful:
Section 11.4.8: Bitwise NOT (~)
Section 11.7: Bitwise Shift Operators (<< and >>)
Section 11.10: Binary Bitwise Operators (| and &)
Note that JavaScript's numbers are all floating point (see Section 8.5, The Number Type, in the specification), but the bitwise operations are defined in terms of integers. So for instance, the definition of the bitwise NOT operator:
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.
Any decent implementation will be able to handle these efficiently, avoiding unnecessary conversions from Number to internal integer and back.
JavaScript has bitwise operators like other languages. Bitwise operators are, by definition, efficient. You should be able to replicate all the bitwise operations performed in your C program in JS as well.
http://www.eecs.umich.edu/~bartlett/jsops.html