On values, types, variables, functions, and function hoisting
I occasionally help out with OpenTechSchool Zurich, answering questions from folks getting in to programming. There was a question about the difference between function statements and function variables in Javascript.
This is an edited version of the explanation I gave, in case it's useful to anyone else. It was originally in a chat channel with people reading with a wide mix of experience levels.
“All teaching is the process of lying, and then replacing the lies with successively better approximations of the truth.”
Some of what follows is lies. But it lets us get closer to the truth
The original question was:
Especially what confuses me are the functions as there seems to be existent two type of functions like Function expression AND Function statement.
It's not two different types of functions. It's two different ways of referring to a function.
A quick recap of values, types, and variables
I'm going to recap values, types, and variables, to make sure we're on the same page.
It's important to keep these concepts distinct.
At its core, your program is going to be operating on values. A value might be a number like 3, or a string of characters like “hello”, or many other things.
Each value has a type. It's a bit circular, but this is the type of thing it is. 3
's type is a number, "hello"
's type is a string, 3.0
's type is a floating point number, and so on.
You can't have a value without it also having a type. They go hand-in-hand together.
Different programming languages have different types available to them. Javascript doesn't have many
Programs would get pretty confusing if we had to use values all the time. Consider the value 3
; is it supposed to represent a temperature, a calculation, a shoe size, a distance, ... ?
So we have variables.
A variable is a way of labelling a value with a name.
Think of a variable as being like a box. You put the value in the box, and write a label on the outside of the box telling you something about the value inside the box.
And the box has a window on the side, so you can see the value in the box.
You can think of let temperature = 3.0;
as “Create a box, put the value 3.0 in the box, and write 'temperature' on the outside of the box”
Some programming languages require you to say what type of value you're going to put in a variable before you can use the variable.
Javascript does not. You can create a variable containing a string, and then put a number in the same variable later.
let x = "some string";
...
x = 3; // <-- this is allowed
Python is similar to Javascript.
In some other languages, like Java you need to specify the type of value you can store in the variable. Later, if you try and put a value with a different type in the same variable you will get an error.
String x = "some string";
...
x = 3; // <-- this is not allowed in Java,
// x can only contain values with type "String",
// and the type of 3 is "int"
Our three key concepts now are:
- values, like 3, “hello”, and 3.0
- types, like number, or string. Each value has a type
- variables, ways of labelling values so they have meaning and can be reused
Javascript can tell you what the type of a value is using the typeof
operator.
> console.log(typeof 3);
number
> console.log(typeof 3.0);
number
> console.log(typeof 'hello');
string
> let x = 4;
> console.log(typeof x);
number
The last line is interesting. It will print number
, but that's not the type of the variable, it's the type of the value in the variable.
What does this have to do with functions?
Functions are also values, and have types
This is both important, and confusing.
Consider a function like this:
function foo() {
return 42;
}
What's the type of the function?
Most people will say “number” — the function returns a number, so when they see the question “What's the type of the function?” they actually see “What's the type of the value returned by the function?”.
And the function does return a number. So it's the correct answer to the second question.
To be fair, most of the time, it's what the question actually means, so it's a reasonable assumption.
But it's the wrong answer to the first question. The type of a function in Javascript is function
.
You can check this with:
> function foo() { return 42; }
> console.log(typeof foo);
function
ASIDE: Javascript is pretty limited in this respect. Other languages will be more specific, and tell you the type is
function () -> number
or similar, which means it's a function that takes no arguments and returns a number.
Because it has a type a function is also a value.
For the purposes of this example you can imagine a function's value is all of the code in the function.
If a function is a value, and it has a type, then it's no different to 3
, or "hello"
, or 3.0
, which are also values with types (every value has a type!).
This means we can put a function in a variable. Like this.
let my_func = function() {
return 42;
};
And we can call the function in this variable.
> console.log(my_func);
ƒ () {return 42;} // <-- output
Wait, what's going on with the output? That's not 42
.
Imagine we had done this:
> let x = 3;
> console.log(x);
3
Javascript is taking the variable x
, and telling you the value inside the variable. 3
in this case.
That's exactly what's happening with the console.log(my_func);
example. The value of the function is being shown to you as ƒ () {return 42;}
If you want to call the value of the function in the variable you have to use ()
the same as any other function call.
> console.log(my_func()); // <-- note the extra ()
42
And if you try and use a value that isn't a function type you get an error message.
> let x = 3;
> x();
Uncaught TypeError: x is not a function
The error message could be more precise. It should really say “The value in x is not a function”, because in both cases neither x
or my_func
are functions, they are variables. It's the value inside the variable that's important.
Like I say, it's important to keep the value / type / variable distinction clear.
Function statements and function expressions
Knowing all this we can look at the difference between function statements and function expressions.
A function statement looks like:
function foo() {
return 42;
}
A function expression looks like:
let foo = function() {
return 42;
};
These both do the following identical things:
- Create a variable
- ... called
foo
- ... that contains a value
- ... the value is
ƒ () {return 42;}
- ... and the the type is
function
.
The only difference is where the variable is visible from.
Hopefully you're familiar with variable visibility already. It means that this code won't work as intended.
console.log(x);
let x = 4;
On line 1 you try and use the value in the variable x
, but that variable is only created later, on line 2.
It's the same thing with function expressions. If you tried this:
console.log(foo());
let foo = function() { return 42; };
that won't work either. The variable foo
is used on line 1 before it's created on line 2.
But this next example does work (in a program, not from the Javascript console).
console.log(foo());
function foo() {
return 42;
}
When you stop and think about it, this is a bit weird. We're able to use the function in the code before we've defined it. How?
Javascript calls this function hoisting.
A function declared using a function statement is “hoisted up” (for non-native English speakers, “hoist” is a synonym for “lift”) so it's available before any code that uses it.
A function declared using a function expression is not hoisted, so it's available only after it's been declared.
And that's the difference.