Let's analyze this step by step.
The first call is to mystery
with an argument of 3
.
What does mystery
do? It defines a variable secret
with the value 4
and then it adds 2
to input
.
So after the first two lines of mystery
, you have:
secret = 4;
input = 5;
Then you have a nested function called mystery2
which takes in an argument called multiplier
. In the first line it multiplies input
to multiplier
, and then returns secret * multiplier
. We don't know the values of multiplier
, but we do know the values secret
and input
. You might be wondering how that is. Well, in JavaScript when you create a closure, it is lexically bound to the current scope. This is just a fancy way of saying that the closure "knows" about all local variables that were created in the same scope that the closure itself was created. This behavior applies to nested functions as well which is why they can behave as closures in JavaScript. So what this means is that mystery2
, when it is eventually called, will have secret
set to 4
and input
set to 5
. So this mystery2
, which knows about these two values, is returned from mystery
. So after execution, the variable hidden
doesn't contain a value, instead it contains a reference to an instance of mystery2
where the values of secret
and input
are the ones I mentioned earlier.
What is the advantage of this? The advantage is that you can have multiple copies of mystery2
, which "know" different values of input
based on what was passed into mystery
. So here, mystery
is sort of behaving like a constructor for mystery2
.
Now we have hidden
pointing to an instance of mystery2
. So in this case hidden
is sort of an alias for our own special copy of mystery2
.
In the next line, you call mystery3
and pass in hidden
as an argument. What happens inside mystery3
? Well mystery3
accepts a parameter called param
, then it does something similar to mystery
; it returns a function. What does this function do? It accepts a parameter called bonus
. Then it does param(6) + bonus
.
What does that mean?
What is param
? It is the argument that was passed into mystery3
. Since mystery4
behaves like a closure, it "knows" about param
. But actually, what is param
? Well, param
is hidden
, which points to our special instance of mystery2
! Now here is where we actually evaluate mystery2
: we call it with an argument of 6
, which will be the value of multiplier
. So now you have multiplier *= input
. The value of input
that mystery2
"knows" is 5
. So we basically have 6 * 5
, which means that multiplier
is now set to 30
. Then we return secret * multiplier
, which is 4 * 30
, which is 120
. So what this means is that param(6)
returns 120
, which we then add to bonus
. Keep in mind that this will happen only when we actually execute mystery4
.
When do we execute mystery4
? Well after we call mystery3
, we return a copy of mystery4
, which is then assigned to jumble
. After that we call jumble(2)
. So what is jumble
? It is essentially this:
function mystery4(bonus) {
return param(6) + bonus
}
What is param
? Well, that is basically mystery2
:
function mystery2 ( multiplier ) {
multiplier *= input;
return secret * multiplier;
}
Let's go over the calculations again. When we call param(6)
, we basically have multiplier
set to 6
inside mystery2
. mystery2
"knows" that input
is 5
(it is what we calculated inside mystery
). So multiplier *= input
, means that multiplier
is now 30
. Then we do secret * multiplier
, which is 4 * 30
, which is 120
. So the return value of param(6)
is 120
. To this value we add bonus
inside mystery4
. We called mystery4
with an argument of 2
, so we have 120 + 2
, which means that the final result is 122
.
Hope this helps you out!