-2

I was intrigued to read more about the eval() function at MDN , and encountered the following passsage

If the argument of eval() is not a string, eval() returns the argument unchanged.
In the following example, the String constructor is specified and eval() returns a String object rather than evaluating the string.

eval(new String('2 + 2')); // returns a String object containing "2 + 2"
eval('2 + 2');             // returns 4

It didn't make sense to me as "if eval doesn't evaluate its argument if it's not a string, then why did it create a new object instance !?"

polendina
  • 110
  • 3
  • 10
  • *"then why did it even create a new object instance"*: `eval` does not create a new object instance (when you give it an object). Why do you think that? – trincot Dec 01 '20 at 21:57
  • 2
    I wouldn't waste much time worrying about `eval()`. You can almost always do things a better way. Given the problems that `eval()` can introduce (code injection, more difficult debugging, and, allegedly, poor performance) spend your time elsewhere. –  Dec 01 '20 at 22:01

3 Answers3

0

The type that is returned from new String('2 + 2') is "object".

console.log( typeof new String('2 + 2') )
console.log( typeof new String('2 + 2').toString() )

Since this is an object,

If the argument of eval() is not a string, eval() returns the argument unchanged.

If you specifically cast the String object to the string primitive with .toString(), it functions as you'd expect.

console.log(eval('2 + 2'));   
console.log(eval(new String('2 + 2')));
console.log(eval(new String('2 + 2').toString()));
Samathingamajig
  • 11,839
  • 3
  • 12
  • 34
0

Your examples just works as they should.

Argument of the first eval is an object, not a primitive variable. String object in Javascript is explained in this question

eval(new String('2 + 2')); // So eval doesn't do anything here and return argument without any operation.

Argument of the second eval( is a pure string. No matter what's inside, eval will directly execute as a javascript code.

eval("new String(2+2)") // This will first calculate 2 + 2 and create a new string object with argument 4. 

Last one, it's a string, so eval will directly execute it as a javascript code as in the second example. The difference is, String object now accepts a string '2 + 2'

eval("new String('2 + 2')"); // returns a string object with a string argument. 

Hope this explanation helped.

tolga
  • 2,462
  • 4
  • 31
  • 57
  • yes , my problem is with the first and third example I.E., is that the it says eval() doesn't do anything and return the argument without any operations ; i interpreted that as the statement new String("2+2") will be literally returned in the console output , not a new String object like the output of the third example – polendina Dec 01 '20 at 22:52
  • Look, in the third example it's a string, eval doesn't care the content of the string but starts executing as javascript if it's a string, so the only one which will never be executed by eval is the first example. Others are interpreted as javascript lines. – tolga Dec 02 '20 at 10:23
0

It is quite straightforward. You can dissect eval as follows:

if (typeof argument === "string") return <evaluation of string>;
else return argument; // eval just returns what it gets

So your examples:

    eval(new String('2 + 2'));

You can split this into two statements:

let arg = new String('2 + 2');
console.log(typeof arg); // object
console.log(eval(arg) === arg); // true, because typeof arg is not "string"

The other two example pass a type string to eval:

let arg = "new String(2+2)";
console.log(typeof arg); // string
// Now we get evaluation of 2+2 and String constructor is called:
console.log(eval(arg)); // a String object (that's what the constructor produces)

In the third example, the string '2 + 2' is evaluated, which is the string "2 + 2". The rest is the same as the second example.

Note that a String object is not of type "string", but of type "object".

trincot
  • 317,000
  • 35
  • 244
  • 286
  • "// eval just returns what it gets" is see the explanation that way : internally if the argument is a string the interpreter execute the string argument -as part of the eval() function e.g., example 2 , 3, and if the argument is not enclosed in quotes the interpreter still execute it -separately- e.g.,example 1 , is that the how it works – polendina Dec 01 '20 at 23:29
  • sorry , forgot about callback functions – polendina Dec 02 '20 at 02:33
  • *"...is not enclosed in quotes, the interpreter still executes it"*: that has nothing to do with `eval`;: if you would not wrap that expression with `eval()`, it would also evaluate`new String`... That is how JS works: first the expression is evaluated. If that happens to be a string literal, there is nothing to it. If it happens to be a call of a constructor, then that call is executed. Once the expression has been evaluated, it is passed to `eval`. Only at that point `eval` does its thing: it the expression evaluated to string, then it is parsed and executed by `eval`. – trincot Dec 02 '20 at 06:45
  • I cam across my previous questions, and found some of them to be utterly useless and weird. There was others questions of mine that was discontinued without clear answer so i outright removed them. As for this question, the answer oddly enough makes no sense now. after some familiarity with js, i'm sure the more appropriate one has to do with how js parse and struct the control flow of tokens for invocation. – polendina Apr 16 '22 at 00:58
  • Did you realize my answer refered to a part of your question that you edited out in 2021? I can understand that as you read it now it makes little sense... as that connection is lost since that edit. – trincot Apr 16 '22 at 01:28