If you look at the Mozilla documentation on Operator Precedence, you can see that the "new" operator has the same precedence - 19 - as member access and function calls.
The one place where this concept of precedence and the "new" operator keeps coming up for me is when I create a new Date object in order to access the current UTC tick count:
NOTE: In modern browsers, and Node.js, you can simply use Date.now().
I think the trick here is that the associativity for the "new" operator is "N/A" (not applicable). Which, in my mind, means that the "new" operator is actually a little bit "black magic."
... as being equivalent to:
( new global.Date() ).getTime()
new echoValue( Date )().getTime()
... where echoValue() is a function that returns its first argument?
new (echoValue( Date ))().getTime()
As you can see, we've wrapped our echoValue() call in parenthesis in order to indicate that it has a higher precedence - 20 - than the "new" operator - 19. Now, the echoValue() Function will be evaluated first and echo back the Date object, which becomes the left-most newable object in the expression.
This might look really silly; but, one place this has practical implications is when you need to access a constructor returned by a require() call in Node.js:
new (require( "my-module" )).MyModule();
AN ASIDE ON TEAMWORK: Parenthesis are your friend. Operator precedence is an interesting topic; but, you should absolutely never assume that it is second nature to your teammates. Your 6th grade Algebra teacher may have demanded that you know that multiplication comes before addition (remember PEMDAS); but, when you're working with a team, never never ever depend on operator precedence! Always use parenthesis to spell out exactly what you are expecting to happen.
Now it's all cristal clear.
Kyle Simpson shed's light on that `new` magic here https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch2.md#new-binding
Excellent sir -- glad you enjoyed it.
Kyle Simpson is an awesome resource! I keep meaning to read his books. He always forces me to think more deeply about how things work and about what kind of assumptions I'm making.
I wish the YDKJS series and Eloquent JS existed when I started JS, both are just insanely great resources.
Your comments at the beginning and end of this article, regarding liberal use of parens for clarity and readability, echo statements I've made to my own team numerous times. Even though certain statements make for perfectly legal assignments according to the language itself, parens are free, will be removed during minification/obfuscation, and greatly aid in readability and signaling the actual intent of how a statement should execute, both to other engineers, and to future you, when you have to come back and maintain it 6+ months from now :) I was glad to see that mentality validated here :)
"until it hits a Function with arguments (ie, using parenthesis)."
Huh? Your example of "Date()" uses parentheses but doesn't include any arguments. The part of MDN you quoted said "argument list", where I guess a "list" could be empty, but "with arguments" implies a non-empty argument list.
It's like my Dad used to say me when crossing the street - always let the cars go. With regard to "rightive way", he always said, "You might be right -- dead right" (indicating that I might be right to cross, but the car will still kill me).
Ok, maybe not a great analogy - but the point is, doing "good" for your team is not the same as being "right" in the code.
I'm not sure how to interpret that :D Do you mean sometimes being "dead right" in the code can be bad for the team if it's done too militantly? Or too nitpicky? If so, I would agree, and always try to phrase it in a constructive fashion (or make my biggest nitpicks enforceable via linting so that I don't have to have that conversation in the first place). On some occasions, if there have been a few back-and-forths in a code review, with subsequent commits to clean things up, sometimes I'll let the lesser items go, and fix them myself at a later time, rather than seem like I'm trying to beat them down with review comments over and over :)
If you meant something else, I missed it :)
Good catch - I think I miswrote there. I think what I mean to write was a "function with parenthesis". I was trying to differentiate accessing a function as an object as opposed to invoking it. For example, if "Foo" is a constructor, you can certainly store properties on that constructor (since it inherits from Object):
In this case, "Foo" is a function, but it has no parenthesis - it's being accessed an object. Which is different than:
... in which it is being invoked.
Good catch though, I think I was caught up in trying to thinking about it that I didn't get the right words down on paper.
Yeah - that's what I meant. Just wasn't getting the right words down. Just saying your code can be "right", but it doesn't mean it's "right for the team."
It's not magic.
Level 19 new operator syntax:
new <sub-expression-1> ( <sub-expression-2> )
The sub-expression-2 can be anything.
The sub-expression-1 can be level 19-20 operators (chain), because the precedence, and a result must be an object with a constructor. But the syntax of the function call matching with the new operator syntax ending. Resulting three cases:
- If the result - before the first backet - is a constructor, the expression ends,
- if it's a function, the expression continue,
- and if both, the function call win.
And, the bracket and the new operator must be first in a subexpession, because they are non-associative, not "chainable" to left-to-right.
This might be what you are saying -- I think maybe I am not fully understanding your explanation. But, given my confusion about the topic at its onset, this is not surprising :D
I wrote incorrectly that
<sub-expression-1> could contain function calls, I messed up something in a console when i tested. Instead, try some example from your blog post on https://astexplorer.net, it's much better tool for it.
That site looks really interesting. I know of AST (Abstract Syntax Tree); but, I've never really thought much about it, other than it probably makes for better work-flows than parsing via Regular Expressions :D