It works fine:
const foo = 1; // any number, string, bolean or object
(() => console.log('stuff'))()
But it doesn't work without semicolon:
const foo = 1 // TypeError: 1 is not a function
(() => console.log('stuff'))()
Hm...
Should not the call of an anonymous function be treated as a separate instruction in the case when the first bracket can not be interpreted as a correct continuation of the previous instruction?
Yes, but it's only about syntactically correct continuations.
1(() => console.log('stuff'))()
is a syntactically correct expression and parses as "call 1 with an argument of () => console.log('stuff'), then call the result of that without arguments". This throws an exception at runtime (1 is not function, so it can't be called), but it's still a valid expression.
You should alway use semicolons. If you do not add them, Javascript will guess where to insert them and will lead to errors.
In your case, it is interpreting that you are calling a function.
A good article on the topic on how semicolons are automatically inserted:
The norm: The parser treats every new token as part of the current
statement, unless there is a semicolon that terminates it. The
following examples show code where you might think a semicolon should
be inserted, but isn’t. This illustrates the risks of omitting
semicolons.
No ASI:
a = b + c
(d + e).print()
This does not trigger ASI, because the opening parenthesis could follow c in a function call. The above is thus
interpreted as:
a = b + c(d + e).print();
…when the first bracket can not be interpreted as a correct continuation of the previous instruction?
But it can - as you can see, the code parses just fine, and executes. That it will throw a runtime exception when no semicolon isn't inserted doesn't matter to the ASI, it cannot know while parsing.
in javascript, it doesn't matter how many spaces you have, it will just be treated as one space only.
in your second code snippet, it just actually equals:
const foo = 1 (() => console.log('stuff'))()
which means you invoke a function called '1' and pass '()=>console.log('stuff')' as an argument. but apparently 1 is not a function, so it throw an error, hope make sense to you
Related
For the past few hours I have been trying to find the difference between the 3, not just the difference, I also have been trying to find out which are sort of synonymous, MDN calls all declarations "statements", so I presume that is true. However, none of the articles and SO questions I read provided me with a cheatsheet of sorts to distinguish between the 3 (or the 2, expressions vs statements).
Something I have noticed with statements is that they all somehow involve a special JavaScript keyword like break or for or var. The articles say that an expression evaluates to something, while a statement performs an action. What is a function then ? Is it a statement-expression hybrid (since it both performs an action when called, and returns a value) ? Right now, I am assuming that this is not the case since a function call does not involve a JavaScript keyword.
And then there are declarations, is every declaration also a statement ?
I am also aware of expression statements like 20 + 5 * 2 / 3;, but aren't these virtually useless ? Why would anyone pollute their code with a line like this ?
I would be more than glad if someone could ask the above questions (or at least some of them), or if someone could provide me with some sort of a cheatsheet. Why is there so little material on a topic that appears to be so simple in such a popular language ?
There are standard definitions of these terms that all languages, including JS, follow. My takes on them are the following:
An expression produces a value and can be written wherever a value is expected.
A statement on the other hand is is a standalone unit of execution. It does not return anything.
A declaration is a statement in which a value is assigned to a variable.
All declarations are statements, but not all statements are declarations.
Most statements and all declarations contain expressions.
Javadoc also gives nice, succinct definitions:
An expression is a construct made up of variables, operators, and method invocations, which are constructed according to the syntax of the language, that evaluates to a single value.
Statements are roughly equivalent to sentences in natural languages. A statement forms a complete unit of execution.
Now, your theory on keywords being necessarily involved is incorrect. Here is a statement that includes a keyword:
break;
And here is one that does not:
foo();
In the first example I execute a break, whereas in the second one I call a function. Both are statements, however only one includes any special keyword.
A function is not a statement. A function call is a statement, as demonstrated above. In the case of a function that returns something, the call can also be a declaration:
var bar = foo();
And for your final question, the reason there is so little material out there on this is because this is merely an issue of semantics. People do not linger on the exact definitions of these terms.
For further clarification, I recommend taking a look at this blog post by Axel Rauschmayer that specifically talks about the difference between statements and expressions in JS.
For the past few hours I have been trying to find the difference between the 3, not just the difference, I also have been trying to find out which are sort of synonymous, MDN calls all declarations "statements", so I presume that is true.
A declaration is any construct that "declares" a variable name into existence at compile/load time before the program executes. All declared names in their respective scopes are therefore known in advance.
Statements and expressions differ from each other in that the former does not produce a value a result, whereas the latter does. So an expression may be used anywhere a value is expected, and a statement may not be used in those places.
An expression statement is one where the statement is a single expression, or several included in an expression that requires zero or more sub-expressions. While the expression(s) produce a result, the statement does not.
Here's an expression:
x = foo() + 2
A full expression statement could be explicitly shown by adding a semicolon to the end.
x = foo() + 2;
The first example can be wrapped in a set of parens, because the parens as a grouping operator expects an expression, often provided as several expressions joined by the comma operator.
The second example can not be wrapped in parens (if you include the semicolon) because then it is a statement, and does not produce a value, which the grouping operator expects to receive and return as its own value.
Something I have noticed with statements is that they all somehow involve a special JavaScript keyword like break or for or var.
While most statements do involve a keyword, not all do. Most notably, the block statement has no keyword. Instead it uses a set of curly braces to delimit its start and end.
The articles say that an expression evaluates to something, while a statement performs an action. What is a function then ? Is it a statement-expression hybrid (since it both performs an action when called, and returns a value) ? Right now, I am assuming that this is not the case since a function call does not involve a JavaScript keyword.
There are three kinds of functions in JS. If you're talking about the ones that use the function keyword, then the may be either a declaration or an expression depending on its context.
If the function is used where an expression would be expected, then it's evaluated as an expression that returns a new function object. If not, then it is expected to be a declaration, which basically creates a variable with the function object assigned to it. As a declaration, a function name is required (for the variable name). As an expression, it's optional.
I am also aware of expression statements like 20 + 5 * 2 / 3;, but aren't these virtually useless ? Why would anyone pollute their code with a line like this ?
If the resulting value is ignored, it would be useless, given that example. But here's another expression statement.
foobar();
Now we have a side effect from the function call, which is most likely desired and useful.
Let's talk about expressions first. As you say, an expression is something that evaluates to a value. A function is a value. A function call, on the other hand, is an expression.
I don't agree with the characterization of a statement as something that "performs an action". As you say, calling a function involves running the function body, which consists of statements and declarations, so it performs actions "on the inside".
A better way to look at it is that expressions, statements, and declarations are syntactic categories. They arise from trying to describe the structure of the JavaScript grammar. See e.g. the ECMAScript 8 specification on expressions, statements, and declarations.
An expression statement like 20 + 5 * 2 / 3; is indeed useless because it has no effects, and the only point of a statement is its effects. But there are other kinds of much more useful expression statements:
a function call: foo();
assignment: x = 42; (= is an operator and can be used in expressions)
increment/decrement: i++; (similarly, ++ is an operator)
Statements other than expression statements tend to start with a special keyword to avoid syntactic ambiguity: The parser wants to be able to tell what kind of construct it is dealing with right from the start. Hence we get:
if statements: if (EXPR) STMT
while statements: while (EXPR) STMT
return statements: return; or return EXPR;
etc.
However, there are some statements that don't start with a keyword:
the empty statement: ;
a block: { ... }
Finally, declarations. In JavaScript the distinction between statements and declarations is somewhat arbitrary. The grammar distinguishes between the two, but in practice you can often treat them the same (e.g. the contents of a block statement are defined as a sequence of statement list items, and a statement list item is defined to be either a statement or a declaration). Declarations include:
function declarations: function foo() { ... } (including variants such as generators (function* foo() { ... }) and asynchronous functions (async function foo() { ... }))
let and const
class declarations
(But for some reason var foo; is classified as a statement, not a declaration.)
I am curious how the typescript compiler is interpreting the colon in the incorrect call to the function foo.
const foo = (bar: boolean) => {
return bar;
}
foo(bar: true) // ERROR "Expected 1 arguments, but go 2."
This implies that it is interpreting both "bar" and "true" as arguments. To be clear, I am just curious how the compiler is parsing this.
As a follow-up, are there any legitimate uses of a colon in a function call except for in an expression that would result in an argument as in:
const baz = (bin: {bar: boolean})=>{
return bin.bar
}
baz({bar: true})
There are two errors generated for that line. One is indeed that the function expects two arguments, but the other one is that , was expected (this is the error you will see if you run the compiler).
The language service tries to offer as much diagnostics as possible even on invalid code.
The parser will try to parse bar as an argument (ie an expression) when it reaches the : it will stop parsing the argument expression as : can't be part of such an expression (at this time anyway). Then the compiler will continue to parse what it expects will be an argument list, and expect the ,, but finding the : instead. Now this is not a tragedy, the compiler will continue to parse the argument list, and interpret true as the next argument expression.
The semantic checks, will then see this call (with two arguments) as an attempt to call a function with one parameter with two arguments and give an error on that.
The reason you are probably seeing in your IDE the semantic error over the syntactic one is because the semantic error is associated with the whole call(foo(bar: true)) while the syntactic error is associated with just : (and if you hover over : you will see the ',' expected error)
As to your follow-up : can't be used directly in the argument list (like it can for example in C# for named arguments). The only valid use is if you use an object literal.
For the past few hours I have been trying to find the difference between the 3, not just the difference, I also have been trying to find out which are sort of synonymous, MDN calls all declarations "statements", so I presume that is true. However, none of the articles and SO questions I read provided me with a cheatsheet of sorts to distinguish between the 3 (or the 2, expressions vs statements).
Something I have noticed with statements is that they all somehow involve a special JavaScript keyword like break or for or var. The articles say that an expression evaluates to something, while a statement performs an action. What is a function then ? Is it a statement-expression hybrid (since it both performs an action when called, and returns a value) ? Right now, I am assuming that this is not the case since a function call does not involve a JavaScript keyword.
And then there are declarations, is every declaration also a statement ?
I am also aware of expression statements like 20 + 5 * 2 / 3;, but aren't these virtually useless ? Why would anyone pollute their code with a line like this ?
I would be more than glad if someone could ask the above questions (or at least some of them), or if someone could provide me with some sort of a cheatsheet. Why is there so little material on a topic that appears to be so simple in such a popular language ?
There are standard definitions of these terms that all languages, including JS, follow. My takes on them are the following:
An expression produces a value and can be written wherever a value is expected.
A statement on the other hand is is a standalone unit of execution. It does not return anything.
A declaration is a statement in which a value is assigned to a variable.
All declarations are statements, but not all statements are declarations.
Most statements and all declarations contain expressions.
Javadoc also gives nice, succinct definitions:
An expression is a construct made up of variables, operators, and method invocations, which are constructed according to the syntax of the language, that evaluates to a single value.
Statements are roughly equivalent to sentences in natural languages. A statement forms a complete unit of execution.
Now, your theory on keywords being necessarily involved is incorrect. Here is a statement that includes a keyword:
break;
And here is one that does not:
foo();
In the first example I execute a break, whereas in the second one I call a function. Both are statements, however only one includes any special keyword.
A function is not a statement. A function call is a statement, as demonstrated above. In the case of a function that returns something, the call can also be a declaration:
var bar = foo();
And for your final question, the reason there is so little material out there on this is because this is merely an issue of semantics. People do not linger on the exact definitions of these terms.
For further clarification, I recommend taking a look at this blog post by Axel Rauschmayer that specifically talks about the difference between statements and expressions in JS.
For the past few hours I have been trying to find the difference between the 3, not just the difference, I also have been trying to find out which are sort of synonymous, MDN calls all declarations "statements", so I presume that is true.
A declaration is any construct that "declares" a variable name into existence at compile/load time before the program executes. All declared names in their respective scopes are therefore known in advance.
Statements and expressions differ from each other in that the former does not produce a value a result, whereas the latter does. So an expression may be used anywhere a value is expected, and a statement may not be used in those places.
An expression statement is one where the statement is a single expression, or several included in an expression that requires zero or more sub-expressions. While the expression(s) produce a result, the statement does not.
Here's an expression:
x = foo() + 2
A full expression statement could be explicitly shown by adding a semicolon to the end.
x = foo() + 2;
The first example can be wrapped in a set of parens, because the parens as a grouping operator expects an expression, often provided as several expressions joined by the comma operator.
The second example can not be wrapped in parens (if you include the semicolon) because then it is a statement, and does not produce a value, which the grouping operator expects to receive and return as its own value.
Something I have noticed with statements is that they all somehow involve a special JavaScript keyword like break or for or var.
While most statements do involve a keyword, not all do. Most notably, the block statement has no keyword. Instead it uses a set of curly braces to delimit its start and end.
The articles say that an expression evaluates to something, while a statement performs an action. What is a function then ? Is it a statement-expression hybrid (since it both performs an action when called, and returns a value) ? Right now, I am assuming that this is not the case since a function call does not involve a JavaScript keyword.
There are three kinds of functions in JS. If you're talking about the ones that use the function keyword, then the may be either a declaration or an expression depending on its context.
If the function is used where an expression would be expected, then it's evaluated as an expression that returns a new function object. If not, then it is expected to be a declaration, which basically creates a variable with the function object assigned to it. As a declaration, a function name is required (for the variable name). As an expression, it's optional.
I am also aware of expression statements like 20 + 5 * 2 / 3;, but aren't these virtually useless ? Why would anyone pollute their code with a line like this ?
If the resulting value is ignored, it would be useless, given that example. But here's another expression statement.
foobar();
Now we have a side effect from the function call, which is most likely desired and useful.
Let's talk about expressions first. As you say, an expression is something that evaluates to a value. A function is a value. A function call, on the other hand, is an expression.
I don't agree with the characterization of a statement as something that "performs an action". As you say, calling a function involves running the function body, which consists of statements and declarations, so it performs actions "on the inside".
A better way to look at it is that expressions, statements, and declarations are syntactic categories. They arise from trying to describe the structure of the JavaScript grammar. See e.g. the ECMAScript 8 specification on expressions, statements, and declarations.
An expression statement like 20 + 5 * 2 / 3; is indeed useless because it has no effects, and the only point of a statement is its effects. But there are other kinds of much more useful expression statements:
a function call: foo();
assignment: x = 42; (= is an operator and can be used in expressions)
increment/decrement: i++; (similarly, ++ is an operator)
Statements other than expression statements tend to start with a special keyword to avoid syntactic ambiguity: The parser wants to be able to tell what kind of construct it is dealing with right from the start. Hence we get:
if statements: if (EXPR) STMT
while statements: while (EXPR) STMT
return statements: return; or return EXPR;
etc.
However, there are some statements that don't start with a keyword:
the empty statement: ;
a block: { ... }
Finally, declarations. In JavaScript the distinction between statements and declarations is somewhat arbitrary. The grammar distinguishes between the two, but in practice you can often treat them the same (e.g. the contents of a block statement are defined as a sequence of statement list items, and a statement list item is defined to be either a statement or a declaration). Declarations include:
function declarations: function foo() { ... } (including variants such as generators (function* foo() { ... }) and asynchronous functions (async function foo() { ... }))
let and const
class declarations
(But for some reason var foo; is classified as a statement, not a declaration.)
Looking at these articles from Mozilla's JavaScript guide:
Expressions
Statements
expressions are also considered assignment statements. In fact, in the second article one can read "any expression is also a statement". Being acquainted with other programming languages, I thought that expressions are always values, but they never cause side effects like statements would do. In other words, 7, 7 + 8, "string", etc., are expressions, because they don't change the state, but a = 7 is a statement, since a variable has now been defined (i.e. a state has changed).
Why would Mozilla not differentiate between the two in JS?
I believe you are taking the terms "expression" and "statement" too literally. "Expressions not changing any state" is a very tough requirement for a programming language.
A thought experiment: In 7 + 8 substitute 8 with a function call to
var globalVar = 0;
function my8() {
globalVar = globalVar + 1;
return 8;
}
Is 7 + my8() a statement or an expression? There is no obvious state change happing here, but still my8 performs a state change. Using the "no side-effects" definition it would be impossible to decide if 7 + my8() is a statement or an expression without analyzing the code of the my8 function. Of course it would be possible to simply prohibit any state change as part of a function call, but that is not the way of JavaScript.
In my experience most languages define "everything which returns a value" as an expression and a statement, everything else as just a statement.
To answer your question "Why would Mozilla not differentiate between the two in JS?":
I think they do, but not in the manner you expected. To consider "everything which returns a value" an expression seems to be the most practical approach.
Also there is no contradiction between a chunk of code being a statement and an expression at the same time. That is simply how Javascript and many other languages work. Of course it is always possible to draw a more strict line between those two.
Examples:
Assignments return values, so this is possible:
a = b = c = 1;
It can be written in the more obvious form:
a = (b = (c = 1));
Because of that an assignment is considered an expression (and also a statement).
On the other hand:
if (true) { };
does not return a value (in Javascript!) and therefore is no expression (but still a statement).
An expression is a code fragment that returns some value, Expression (Computer Science):
3; // 3
{}; // Object
func(); // whatever func returns, or undefined if not specified
You can combine expressions into one compound expression:
3 + 7; // 10
{}, []; // Array. Comma operator always returns result of right-most expression
A statement is the smallest valid code fragment that can be compiled or interpreted, Statement (Computer Science):
5; // valid js
You can also combine statements into compound statements:
check || func(); // valid js
{
4 + 9;
"block statement";
}
In the Mozilla documentation, a statement refers to any (compound) statement that is explicitly or implicitly terminated by semi-colon (;).
[,,[],[,[,,],,]]; // Array declaration whose reference is returned (and ignored)
// Multi-dimensional array with empty (undefined) elements
In some programming languages the above example doesn't compile or doesn't get interpreted. Other languages might not allow for the result of an expression not to be catched.
Javascript is very expressive, which is why every expression counts as a valid statement. Some statements are not expressions, like break, return, while, etc. They don't return any value, but they control the program execution flow.
Mozilla does differentiate between the two, or rather the Javascript syntax does.
The only slightly "special" about Javascript is the following:
"any expression is also a statement",
which means that at places where a statement is required in the syntax, an expression can be used directly (but not the other way around). E.g. the following is valid Javascript but invalid in many other similar languages:
if (true) "asfd"
or
foo = function(){
if (5) {
"some text here that won't do anything";
return true;
42; // always good to have that one here!
}
}
whereas statements cannot be used as expressions:
a = (if (true) 5) // does not work "unexpected token 'if'"
They used that "feature" for the strict mode specification without introducing a new keyword or syntax - if you add the expression "use strict" as the first statement in a function body, Javascript is executed in strict mode in supporting browsers.
While expressions evaluate to a value, usually, statements do not. Most statements alter control flow, expressions usually don't (although one could argue that an expression that results in an exception being thrown alters control flow, too).
In Javascript expressions form a subset of all statements.
var a = [1, 2, 3, 4];
var b = [10, 20, 30, 40];
console.log([a, b].length)
[a, b].some(function(x) {
x.push(x.shift())
});
I was extremely surprised today when this code caused
[a,b].some(function(x){ x.push(x.shift()) });
^
TypeError: Cannot call method 'some' of undefined
Obviously the JavaScript 'auto semicolon insertion' is not working as expected here. But why?
I know you might recommend to use ; everywhere to avoid something like that, but the question is not about whether it is better to use ; or not. I would love to know what exactly happens here?
When I'm worried about semicolon insertion, I think about what the lines in question would look like without any whitespace between them. In your case, that would be:
console.log([a,b].length)[a,b].some(function(x){ etc });
Here you're telling the Javascript engine to call console.log with the length of [a,b], then to look at index [a,b] of the result of that call.
console.log returns a string, so your code will attempt to find property b of that string, which is undefined, and the call to undefined.some() fails.
It's interesting to note that str[a,b] will resolve to str[b] assuming str is a string. As Kamil points out, a,b is a valid Javascript expression, and the result of that expression is simply b.
In general, one could say that implicit semi-colon's can easily fail when defining an array on a new line, because an array defined on a new line is interpreted as a property access of the value of the expression on the previous line.
Javascript does only consider new lines to mark the end of a statement if not ending the statement after this new line would cause a parse error. See What are the rules for JavaScript's automatic semicolon insertion (ASI)? and EcmaScript 5 spec for the exact rules. (Thanks to Rob W and limelights)
What happens is the following:
The code get interpreted as
console.log([a,b].length)[a,b].some(function(x){ x.push(x.shift()) });
i.e. all as one statement.
Now parse the statement:
some is called on the value of console.log([a,b].length)[a,b]
the value of console.log([a,b].length)[a,b] is computed by taking the returned value of console.log([a,b].length) (undefined) and then trying to access the property with the name of the value of a,b.
a,b evaluates to the value of b (try it in your console). There's no property with the value of b of undefined, so the resulting value will be undefined as well.
There's no method some on undefined, hence the error.
JavaScript doesn't treat every line break as a semicolon. It usually treats line
breaks as semicolons only if it can’t parse the code without the semicolons. Basically, JavaScript treats a line break as a semicolon if the next non-space character cannot be interpreted as a continuation of the current statement. JavaScript - The Definitive Guide: 6th Ed. section 2.4
So, in your case, it is interpreting the line as something like
console.log([a,b].length)[a,b].some(function(x){ x.push(x.shift()) });
And that is the reason for error. JavaScript is trying to perform array-access on the results of console.log([a,b].length). Depending on the JavaScript engine and the return value of console.log, you might get different errors.
If it is the last statement of the function or flow, you can avoid ';' but it is recommended to put ';' at the end of the each statement to avoid such error.