I understand how the code works, in terms of the results it gives. First, it gets a random number, and, second, using Math.floor() it rounds down the results of Math.Random. Therefore, it's moving from right to left through the code.
Math.floor(Math.Random * num);
In the JavaScript Reference at this url and shown in the image below
it says that, for dot and parentheses, the associativity is "left to right". However, based on the code I excerpted above, I'd say it was "right to left." Please explain
I understand how the code works, in terms of the results it gives. First, it gets a random number, and, second, using Math.floor() it rounds down the results of Math.Random. Therefore, it's moving from right to left through the code.
Math.floor(Math.Random * num);
In the JavaScript Reference at this url and shown in the image below
it says that, for dot and parentheses, the associativity is "left to right". However, based on the code I excerpted above, I'd say it was "right to left." Please explain
Share Improve this question asked Dec 12, 2012 at 22:37 BrainLikeADullPencilBrainLikeADullPencil 11.7k24 gold badges82 silver badges138 bronze badges 2- 2 associativity != execution order – Bergi Commented Dec 12, 2012 at 22:40
-
right to left would mean:
Math.(floor(num))
with error "floor is undefined" – Luca Rainone Commented Dec 12, 2012 at 23:01
2 Answers
Reset to default 3The associativity of operators has nothing to with their execution order, but how they are parsed.
Associativity "Left to right" means that a.b.c === (a.b).c !== a.(b.c)
.
When you have a function invocation, of course the arguments are evaluated first (at least in non-lazy languages like JS) - this is also defined in the specification.
What happens here is:
Math.floor(Math.Random * num);
is parsed into an AST, according to the rules of operator precedence and associativity:
-\ invocation
+-\ function: member operator
| +-- base: variable "Math"
| +-- property: "floor"
+-\ arguments list
+-\ first: Multiplication
+-\ left operand: member operator
| +-- base: variable "Math"
| +-- property: "Random"
+-- right operand: variable "num"
- When evaluated, it happens top-down. The invocation first evaluates its function, calling the member operator on
Math
andfloor
. As this evaluates to a vaild function, it proceeds evaluating the arguments. The multiplication will first fetch its left operand, getting undefined from the member operator onMath
andRandom
; then it fetches the value of the variablenum
. This results inNaN
, and now the floor-function will be called with that, returningNaN
again.
A function cannot be called without its arguments being resolved. This not not a matter of operator precedence (but execution order). The reason why a function call is left-associative is to make e.g. the following call work properly:
foo.bar.baz()
With the operator being left-associative this is equal to
((foo.bar).baz)()
which is equal to the original code. If it was right-associative you'd get the following:
foo.(bar.(baz())
That would obviously do something totally different which would most likely not work at all.
By the way, the function call is on a different precedence level than the member operators. See MDN for a better reference about this topic than the one you linked in your question.