Why does this function expression behave differently than a function declaration?
Consider the following snippet:
function myFunction(a){
console.log(a);
}
myFunction(1);
//1
var oldFunction = myFunction;
function myFunction(b){
console.log('intercept');
oldFunction(b);
}
myFunction(1);
//too many calls, console outputs intercept indefinitely
The code does not work as expected and displays "intercept" indefinitely. Then I searched Stack Overflow and I found out that the following modified code worked as expected:
function myFunction(a){
console.log(a);
}
myFunction(1);//1
var oldFunction = myFunction;
var myFunction = function(b){
console.log('intercept');
oldFunction(b);
}
myFunction(1);
//intercept
//1
My question is, why is the first code not working as expected? I know there are differences between function declarations and function expressions (primarily due to hoisting behavior), but I am still confused.
EDIT: Really wrong behavior in lifting. I understand that the first code works if I execute it like this:
eval(`function myFunction(a){
console.log(a);
}
myFunction(1);
//1
var oldFunction = myFunction;`);
eval(`function myFunction(b){
console.log('intercept');
oldFunction(b);
}
myFunction(1);`);
//1
//intercept
//1
This closes the question. When I execute the code separately, it becomes clear that the myFunction is hoisted.
source to share
This is because of the rise. JavaScript declares function declarations , which means they are hoisted at the top and are declared first and can be used before they are defined:
On the other hand, function expressions do not appear like function declarations. var
is still hoisted , but the value (anonymous function) is not assigned to the variable. To make it clearer, your first snippet essentially looks like this (after the and functions are declared var
):
var oldFunction;
function myFunction(a) {
console.log(a);
}
function myFunction(b) {
console.log('intercept');
oldFunction(b);
}
//myFunction(1);
oldFunction = myFunction;
myFunction(1);
(Side note: I commented out the first call, which throws an error as oldFunction
is undefined when you try to execute myFunction
the first time. The snippet above reproduces what you described in the first snippet of the question)
So, in your code, the first does not work because you have two functions with the same name. So the first one is myFunction
overridden and now it belongs to a newer function. This will cause the code to be rewritten when the function calls itself, forcing it to run indefinitely.
In your second example, this is essentially the following:
var oldFunction;
var myFunction;
function myFunction(a) {
console.log(a);
}
//myFunction(1);
oldFunction = myFunction;
myFunction = function(b) {
console.log('intercept');
oldFunction(b);
}
myFunction(1);
In the lifting function, the target announcement is displayed, not just the name with var
. So, in the second example, the first function is not overridden when you call it the first time. Then, when you execute oldFunction = myFunction
, you assign a oldFunction
reference to myFunction
which is an older function. Doing this will serve an older function. This will log:
intercept
1
As expected and will not be returning forever.
source to share
Only this part works:
function myFunction(a){
console.log(a);
}
myFunction(1);
//1
once you add the rest ...
function myFunction(a){
console.log(a);
}
myFunction(1);
//1
var oldFunction = myFunction;
function myFunction(b){
console.log('intercept');
oldFunction(b);
}
myFunction(1);
//too many calls, console outputs intercept indefinitely
it won't work because for the JS engine it reads like this: (exactly in that order)
var myFunction, oldFunction;
myFunction = function(a){
console.log(a);
}
//immediately overwriting myFunction by
myFunction = function (b){
console.log('intercept');
oldFunction(b);
}
myFunction(1); //this already fails, because `oldFunction` is undefined and therefore can't be called
oldFunction = myFunction;
myFunction(1); //too many calls, console outputs intercept indefinitely
Due to the ascent in your code, this function
function myFunction(a){
console.log(a);
}
is completely excluded and immediately replaced by
function myFunction(b){
console.log('intercept');
oldFunction(b);
}
before only one expression is executed in the code. eg,var oldFunction = myFunction
source to share
In the first sniplet of myFunction code, overridden by new myFunction, and oldFunction refers to the same as the recursive code. But in the second code, the second function myFunction is declared as an intrinsic function that does not override the old myFunction, and when oldFunction is called it only points to the first myFunction.
source to share