2
if(true) {
  tmp = 'abc';
  console.log(tmp);//which should throw referenceError but not

  let tmp;
  console.log(tmp);

  tmp = 123;
  console.log(tmp);
}

This code results in

abc
undefined
123

Why does the first console.log(tmp) not throw an error?


why it should throw a referenceError

In ECMAScript 2015, let will hoist the variable to the top of the block. However, referencing the variable in the block before the variable declaration results in a ReferenceError. The variable is in a "temporal dead zone" from the start of the block until the declaration is processed.


the problem is bable settings,i think.
so,maybe it is a bug of babel? https://github.com/babel/babel.github.io/issues/826
Runjuu
  • 43
  • 5
  • 1
    Why would that throw error when you've defined it `tmp = 'abc';` – Tushar Jun 12 '16 at 14:28
  • Your original usage of `tmp = 'abc'` is implicitly declaring a var. – James Collier Jun 12 '16 at 14:36
  • Please show us your babel settings. This definitely should throw an error, albeit it might not if you are transpiling in loose mode. – Bergi Jun 12 '16 at 14:43
  • May be the problem is babel ? i run this code in chrome,it works – Runjuu Jun 12 '16 at 14:44
  • @Bergi here is my .babelrc file content `{ "presets":[ "babel-preset-es2015" ], "plugins": [ "babel-plugin-transform-es2015-destructuring", "babel-plugin-transform-es2015-modules-commonjs" ] }` – Runjuu Jun 12 '16 at 14:47
  • @BekimBacaj because `let tmp` after the first `console.log(tmp) ` , and `let` prevents hoisting – Runjuu Jun 12 '16 at 14:58
  • related: https://github.com/babel/babel.github.io/issues/826? – Bergi Jun 12 '16 at 15:16

3 Answers3

2

You are correct, in ES6 this does throw an exception. There's two reasons why it doesn't for you:

  • node.js already implemented let - but it works correctly only in strict mode. You should use it.
  • babel does not appear to transpile the TDZ by default, as it is quite complicated and leads to lengthy code. You can however enable it with the es6.blockScopingTDZ/es6.spec.blockScoping option (but I'm not sure whether this worked in Babel 5 only and what happened in Babel 6 to them).
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • sorry,what is TDZ ? – Runjuu Jun 12 '16 at 15:51
  • @Runjuu: the [temporal dead zone](http://stackoverflow.com/q/33198849/1048572) - the thing that causes the access to throw despite being a declared variable. – Bergi Jun 12 '16 at 16:04
  • Babel 6's TDZ is still pretty buggy, so not that many people use it I think. – loganfsmyth Jun 12 '16 at 17:03
  • @loganfsmyth: I don't know much about babel and its versions. Are you saying that it did work in Babel 5, but does not in 6? Do you have some links (maybe a tracking bug report) to back "still pretty buggy"? I have tried searching at https://phabricator.babeljs.io but can't seem to filter by version or sort by date. Also feel free to edit my answer directly if you have something relevant, or post your own :-) – Bergi Jun 12 '16 at 19:58
  • 1
    As for TDZ in Babel 6, this case doesn't seem to be handled. I guess that es6.spec.blockScoping was replaced with https://babeljs.io/docs/plugins/transform-es2015-block-scoping/ plugin but it addresses block scopes only. – Estus Flask Oct 19 '17 at 23:06
0

Statement

tmp = 'abc';

is not elegant but still OK in normal mode (except let keyword which is not allowed outside strict mode). It will simply create global variable. However, the code is not correct and will throw an error only when you executed this code in "strict mode". In this mode you have to declare all variables with one of this keywords:

  • var
  • let
  • const

'use strict'
if(true) {
  tmp = 'abc';
  console.log(tmp);//which should throw referenceError and now it does
                  
  let tmp;
  console.log(tmp);

  tmp = 123;
  console.log(tmp);
}
Przemek
  • 803
  • 4
  • 15
  • i think it is a bug of babel. i run this code without 'use strict' in chrome,it throw a ReferenceError. when i run this code within 'use strict' in babel,it still show me the same result – Runjuu Jun 12 '16 at 15:29
  • but if you can use **let** keyword it means that you are in 'strict mode' and you should see this error as we can see it in above snippet. Babel bug? – Przemek Jun 12 '16 at 15:30
  • By "normal mode" you mean sloppy mode (non-strict)? Notice that in pure ES6 it still is an error, only the implementations (V8) did tolerate it because of backwards-compatibility. – Bergi Jun 12 '16 at 15:39
  • Yes - mean sloppy mode. The the interesting problem here is that this code shouldn't run in any mode. In sloppy it should throw : **SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode**. In Strict mode it should throw **ReferenceError: tmp is not defined** – Przemek Jun 12 '16 at 15:46
-2

No, it shouldn't throw a reference error.

The variable is implicitly declared (in the global scope) when you assign to it.

Then, later, you declare a new variable with the same name but a tighter scope. The new variable is not hoisted because it is declared using let.

I can't give a more precise answer, because you did not explain why you think you should get a reference error.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • The `let tmp;` declares it inside the block statement, and then `tmp = 'abc';` attempts to assign to it before the `let tmp;` line has actually been evaluated, which is an error condition in ES6 for `let`. – loganfsmyth Jun 12 '16 at 20:49