2

I'm seeing a difference in behavior between native es6 and transpiled code.

According to the MDN docs, this code should result in a ReferenceError because I try to use a let-bound variable before it is defined.

let a = b; //expect ReferenceError at runtime
let b = 1;

As expected, running this results in a ReferenceError when I run it in something that natively supports es6, such as Chrome Developer Tools. But if I transpile that with babel, it produces code that doesn't result in a runtime error (Live demo):

"use strict";

var a = b; //no error. Both a & b are undefined
var b = 1;

The behavior of the transpiled code contradicts what the MDN docs say (emphasis mine):

In ECMAScript 2015, let bindings are not subject to Variable Hoisting, which means that let declarations do not move to the top of the current execution context. Referencing the variable in the block before the initialization results in a ReferenceError (contrary to a variable declared with var, which will just have the undefined value).

So I'm wondering:

  1. Is this by design and is there some aspect I'm missing?
  2. Is there a way to get a compile-time failure for this, rather than a runtime ReferenceError or a silent failure of 'undefined'. I notice I get a compile-time error binding to a non-existent variable. Perhaps it could also fail for a not-yet-declared variable?

    let d = e; //compile error: e is not defined
    

Note: there's a related question but I don't think it answers this (or it did but I misunderstood).

dan
  • 9,712
  • 6
  • 49
  • 62

1 Answers1

3

In this snippet

let a = b;
let b = 1;

b is in temporal dead zone. This behaviour cannot be emulated in transpiled code.

To my knowledge, Babel currently doesn't have a plugin to warn against this TDZ issue. Until it will be possible to handle this problem with Babel itself, it can be detected with ESLinter no-use-before-define rule.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565