Using 'let' as a variable name is not throwing any errors in google v8
I was writing some random code in the chrome developer console. For my surprise, chrome let me use let
as a variable name which is completely wrong as let
is a reserved keyword. I need to understand why is this happening.
Scenarios:
var const = 78 //throws an error as expected
var function = 46 //throws an error as expected
var let = 56 //didn't throw an error :O
let //prints 56, which is wrong because 'let' is a keyword
let ab = 90
ab //prints 90 as expected
This flaw exists in node
. But, when I try it in Babel REPL it is throwing an error.
I think this is something to do with Google v8
Solution 1:
A nice write-up of the reasoning behind this can be found in this article by Mohsen Azimi. Here's a quick summary of it.
The following keywords are defined in the JavaScript spec as FutureReservedWord
:
implements interface let package private
protected public static yield
In normal mode, these can be used as variable names without errors; however, in strict mode they are treated as reserved words and will throw the following error:
SyntaxError: Cannot use the reserved word 'let' as a variable name in strict mode.
This is so that pre-ES2015 code doesn't break - if someone had named lots of their variables let
in a legacy app, they probably wouldn't be happy if the JS spec suddenly broke everything.
Solution 2:
The usage of reserved ES6 keywords is forbidden only in strict mode for compatibility reasons.
Babel (via the strict mode plugin) use strict mode by default. In the browser or in Node you can implicitly set strict mode by adding "use strict";
in the beginning of the file or the function.
Running the following code snippet will throw an error in Chrome as you expect it:
"use strict";
var let = 43;
// Throws: Uncaught SyntaxError: Unexpected strict mode reserved word
Solution 3:
This is the joy of a growing language.
The short version is that const
was listed in the ECMAScript 1st Edition as a "future reserved word" which meant that although it didn't have any meaning (then), it couldn't be used for identifiers. (And of course, function
has always been a reserved word.) But let
was neither a reserved word nor a future reserved word, so it could be used for identifiers (and was). It wasn't until the 5th edition that let
was identified as a future reserved word, and then only in the new strict mode ES5 added. (Your example doesn't work in strict mode.) Since let
wasn't reserved, it was potentially used in code in widespread use, and couldn't be retroactively made a purely reserved word in ES2015. So instead, it's still a valid identifier (in loose mode). The parser has to figure out whether it's a declaration or identifier by context. (This has the fun consequence that in loose mode, forgetting to type an identifier after let
isn't a syntax error, let = 42;
works just fine — even if let
isn't declared anywhere [thanks to what I call The Horror of Implicit Globals]. These are good reasons to always use strict mode [because let
can't be an identifier in strict mode, and strict mode doesn't have implicit globals].)
JavaScript also has contextual reserved words. async
is a valid identifier (even in strict mode, and even inside an async
function!), it only has special meaning in places where previously it would have been a syntax error for an identifier to be there:
// Since `blah function` here is a syntax error:
blah function foo() {
}
// ...no valid code would have an identifier in that position, so it was possible
// to add an `async` modifier:
async function foo() {
}
await
is a valid identifier (even in strict mode), unless it's within an async
function; then it's a reserved word. That's possible because async
functions didn't exist before await
, so there was no possibility of an async
function existing that used await
as an identifier. Similarly, yield
is only a reserved word inside generator functions.