What state is kept between JavaScript lines?

2019-04-07 10:12发布

I was wondering what states are kept between two lines of JavaScript code submitted to babel-node. My confusion arises because if you write two lines of code, you can override an variable definition without an error. For example, with babel-node --presets es2015, you can do:

> const a = 1;
undefined
> let a = 2;
undefined

Now if you write it in one line, you get an error:

> const a = 1; let a = 2;
TypeError: repl: Duplicate declaration "a"
...

It seems that in the first case, the state that a is defined as 1 (const variable assignment) is lost (yet not until the second assignment), while in the second case, it is maintained.

What causes the differences here? and which states are maintained?

2条回答
beautiful°
2楼-- · 2019-04-07 10:30

I do not use babel-repl, but it must be something to do with the conversion it is doing because everything works as expected with the regular REPL:

$ node -v
v7.4.0

$ node
> const a = 1;
undefined
> let a = 1;
SyntaxError: Identifier 'a' has already been declared

> const b = 1; let b = 1;
const b = 1; let b = 1;
                     ^
SyntaxError: Identifier 'b' has already been declared

> .editor
// Entering editor mode (^D to finish, ^C to cancel)
const c = 1;
let c = 1;

let c = 1;
        ^
SyntaxError: Identifier 'c' has already been declared
查看更多
地球回转人心会变
3楼-- · 2019-04-07 10:33

Because const and let are new syntaxes, they must be transpiled to the only binding mechanism that was available before ES6: var. In which case, var allows all sorts of haphazard reassignment without generating any kind of warning.

So when you type an expression in babel-node, babel transpiles it, evaluates it, then displays the result. Babel can check for misuse of a const binding at transpile time, which is why you're seeing the error for const a = 1; let a = 2. But const a = 1 and let a = 2, when transpiled/evaluated as separate expressions, will not exhibit the error because babel is not able to detect a problem in either expression alone.


A more visual demonstration of the issue: For every expression expr you type in the babel-node REPL, this is essentially what's happening

evaluate(transpile(expr))
// => someResult

So you won't see an error here

evaluate(transpile('const a = 1'))
evaluate('var a = 1')
// bind a to 1
// return undefined

evaluate(transpile('let a = 2'))
evaluate('var a = 2')
// bind a to 2
// return undefined

But you will see an error here

evaluate(transpile('const a = 1; let a = 2'))
// ERROR during transpile: const a has already been declared
查看更多
登录 后发表回答