Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to catch global constant variable changed error when use eval() function in JavaScript

Tags:

javascript

I try to check whether a "variable" in es6 is constant:

const a = 1;
function test() {
  try {
    a = 2;// throws an error
  } catch (error) {
    console.log(error)
  }
}
test();

But when I use eval() function ,It doesn't throws an error.

const a = 1;
function test() {
  try {
    eval("a = 2;")// not throws an error
  } catch (error) {
    console.log(error)
  }
}
test();

And I make the constant local, the function eval does throw an error as expected.

function test() {
  try {
    const a = 1;
    eval("a = 2;")//throws an error
  } catch (error) {
    console.log(error)
  }
}
test();

And when I use function eval() that cause it doesn't throw an error as expectd. What the functoin eval() have done here ? I run it in Node v6.2.2

const a = 1;

function test() {
  try {
    eval("");
    a = 2; // will not throw an error
  } catch (e) {
    console.log(e)
  }
}
test();

More interesting, I enclose eval() with if (false),it will not throw an error either.

const a = 1;

function test() {
  try {
    if (false) {
      eval(""); 
    }
    a = 2; // will not throw an error
  } catch (e) {
    console.log(e)
  }
}
test();

Anyone can tell me the reason?

Is this a bug in JavaScript?

And how can I catch the global constant variable changed error?

like image 250
zcmyworld Avatar asked Mar 14 '17 08:03

zcmyworld


1 Answers

The fact that eval("a = 2;") in your code doesn't throw a TypeError looks like a bug in V8 (the JavaScript engine in Chrome).

const creates a strict binding via the spec operation CreateImmutableBinding (see Step 16.b.i.1 of GlobalDeclarationInstantiation).

When assigning to an immutable binding (a = 2), a TypeError is meant to be thrown by SetMutableBinding if either 1. The code is in strict mode, or 2. The binding is a strict binding.

So in your code not using eval, you're running in loose mode, but it throws a TypeError anyway because the binding is strict. But V8 doesn't seem to be checking whether the binding is strict when you do eval("a = 2;"). (SpiderMonkey [Firefox] does, and throws the TypeError; as does JScript in IE11. I don't have Edge handy to check Chakra.)

You can make V8 throw the error by making the code in the eval strict:

const a = 1;
function test() {
  try {
    eval("'use strict'; a = 2;");
  }
  catch (error) {
    console.log(error);
  }
}
test();
like image 128
T.J. Crowder Avatar answered Nov 11 '22 10:11

T.J. Crowder