Search code examples
javascriptfunctioneval

Function declaration in the eval does not overwrite the previous one


Let's say we have code like below. The function a is declared twice. and we know the output in the console should be

this is a2

because the second declaration of function a overwrite the previous function a.

function a ()
{
   console.log("this is a1");
}
function a ()
{
   console.log("this is a2");
}
a();

But the things are different when using eval.

Let's say we change the code like below.

eval("function a (){console.log (\"this is a1\")}");

function a ()
{
   console.log("this is a2");
}
a();

the output shows

this is a1

My question is why the function a is not overwritten in this scenario?


Solution

  • For non-strict mode, this is about hoisting; your normal function a() { ... } function declaration gets (invisibly) hoisted to the top of the block, so it functionally happens before the eval.

    $ cat aa.js
    console.log(a.toString());  // If it wasn't for hoisting, this would be an error!
    eval("function a (){console.log (\"this is a1\")}");
    function a (){console.log("this is a2");}
    a();
    
    $ node aa.js
    function a (){console.log("this is a2");}
    this is a1
    

    If you change it to an assignment of a function expression, this doesn't happen, since assignment statements aren't hoisted.

    $ cat aa.js
    eval("function a (){console.log (\"this is a1\")}");
    var a = function a (){console.log("this is a2");}
    a();
    
    $ node aa.js
    this is a2
    

    eval's behavior in general also depends on the strictness mode of the surrounding context (which itself can be modulated depending on how you call eval).

    In strict mode, the function does not leak out of the eval at all:

    $ cat aa.js
    "use strict";
    eval("function a (){console.log (\"this is a1\")}");
    function a (){console.log("this is a2");}
    a();
    
    $ node aa.js
    this is a2