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.

+3


source to share


4 answers


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:

foo(); //logs "in foo"

function foo() {
  console.log("in foo");
}
      

Run code


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);
      

Run code


(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);
      

Run code


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.

+3


source


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

+1


source


The first example oldFunction

is defined as

function myFunction(b){
    console.log('intercept');
    oldFunction(b); // calls `oldFunction` again
}

      

in the second example oldFunction

is defined as

function myFunction(a){
     console.log(a);
}

      

0


source


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.

0


source







All Articles