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?
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