Ah, yeah @snowmonkey has been a bit clearer there. And I should have been a bit more specific: an expression is something that evaluates to a value.
This does not evaluate to a value in JS:
if (condition) {
// something
}
condition
evaluates to a value, it’s an expression. Whatever something
is might also be an expression. But the if () {}
, the actual statement itself? That doesn’t ever evaluate to a value. Same with loops. Same with variable declarations themselves (not what is assigned to them).
An if statement is [almost] saying “if this expression evaluates to true, go to this line in the code, otherwise go to this line”. A loop may be saying “go to this line of code over and over again”. It’s an instruction (as I said “do something” rather than “is something”).
function
s are not like that. They’re a little machine that you can use in your program. You declare the function, then you can call it in your code as many times and in as many places as you want. And they resolve to a concrete value. They are “do something”, but a. the declaration, when evaluated is a reference to a concrete object and b. when they’re executed, they evaluate to a concrete value.
Note that it is a design decision to have conditional/loop statements rather than conditional/loop expressions. It’s not something set in stone in computer science or anything, JavaScript just happens to differentiate between them, copying off several other popular languages. In contrast, in other languages these things are expressions. For example, Rust:
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
assert_eq!(result, 20);
}
Regarding “why would I need to assign a function to a variable”, well, that’s what you’re doing here:
function example () {
// do something
}
There’s a function assigned to an identifier called example
.
Practically speaking, this is basically the same (there are very slight differences, but practically):
const example = function () {
// Do something
}
As is this:
const example = () => {
// Do something
}
There are slight (albeit important) differences to do with scope for arrow functions vs. function
functions, but for the most part, going to be the same.
The most common use for anonymous functions is as callbacks:
[1,2,3].map((n) => n * 2)
And generally you are correct in saying that it’s a kind of shortcut. It makes sense from a developer point of view to have a shorthand for the most common usecase, meaning you don’t need to write this:
[1,2,3].map(function (n) {
return n * 2;
})
But anyway, as I say, there are actual important differences to do with scope, but in many (the majority of?) cases they are, practically speaking, used as shorthand.
The important differences – this goes back to what’s been said: it’s far easier to give explanations when you have specific examples, abstract explanations aren’t likely to be helpful until you encounter the concrete problem they relate to