In principle, a new version of a language is a chance to clean it up, by removing outdated features or by changing how features work. That means that new code doesn’t work in older implementations of the language and that old code doesn’t work in a new implementation. Each piece of code is linked to a specific version of the language. Two approaches are common for dealing with versions being different.
Second, you can permit a code base to contain code in multiple versions, by tagging code with versions. On the web, you could tag ECMAScript 6 code via a dedicated Internet media type. Such a media type can be associated with a file via an HTTP header:
It can also be associated via the
type attribute of the
<script> element (whose default value is
This specifies the version out of band, externally to the actual content. Another option is to specify the version inside the content (in-band). For example, by starting a file with the following line:
Both ways of tagging are problematic: out-of-band versions are brittle and can get lost, in-band versions add clutter to code.
A more fundamental issue is that allowing multiple versions per code base effectively forks a language into sub-languages that have to be maintained in parallel. This causes problems:
We can, however, add new features and make existing features more powerful.
let, which declares block-scoped variables and is an improved version of
var. It does not, however, replace
var. It exists alongside it, as the superior option.
let-declarations are difficult to add to non-strict mode, because
letis not a reserved word in that mode. The only variant of
letthat looks like valid ES5 code is:
Research yielded that no code on the web uses a variable
let in non-strict mode in this manner. That enabled TC39 to add
let to non-strict mode. Details of how this was done are described later in this chapter.
Strict mode was introduced in ECMAScript 5 to clean up the language. It is switched on by putting the following line first in a file or in a function:
Strict mode introduces three kinds of breaking changes:
withstatement is forbidden. It lets users add arbitrary objects to the chain of variable scopes, which slows down execution and makes it tricky to figure out what a variable refers to.
implements interface let package private protected public static yield
ReferenceError. In non-strict mode, a global variable is created in this case.
TypeError. In non-strict mode, it simply has no effect.
argumentsdoesn’t track the current values of parameters, anymore.
undefinedin non-method functions. In non-strict mode, it refers to the global object (
window), which meant that global variables were created if you called a constructor without
let declarations and block-level function declarations. Let’s examine why that is and how to add them, anyway.
letdeclarations in sloppy mode
let enables you to declare block-scoped variables. It is difficult to add to sloppy mode, because
let is only a reserved word in strict mode. That is, the following two statements are legal ES5 sloppy code:
In strict ECMAScript 6, you get an exception in line 1, because you are using the reserved word
let as a variable name. And the statement in line 2 is interpreted as a
let variable declaration (that uses destructuring).
In sloppy ECMAScript 6, the first line does not cause an exception, but the second line is still interpreted as a
let declaration. This way of using the identifier
let is so rare on the web that ES6 can afford to make this interpretation. Other ways of writing
let declarations can’t be mistaken for sloppy ES5 syntax:
ECMAScript 6 wants a function declaration in a block to be local to that block. That is OK as an extension of ES5 strict mode, but breaks some sloppy code. Therefore, ES6 provides “web legacy compatibility semantics” for browsers that lets function declarations in blocks exist at function scope.
static are only reserved in ES5 strict mode. ECMAScript 6 uses context-specific syntax rules to make them work in sloppy mode:
yieldis only a reserved word inside a generator function.
staticis currently only used inside class literals, which are implicitly strict (see below).
The bodies of modules and classes are implicitly in strict mode in ECMAScript 6 – there is no need for the
'use strict' marker. Given that virtually all of our code will live in modules in the future, ECMAScript 6 effectively upgrades the whole language to strict mode.
The bodies of other constructs (such as arrow functions and generator functions) could have been made implicitly strict, too. But considering how small these constructs usually are, using them in sloppy mode would have resulted in code that is fragmented between the two modes. Classes and especially modules are large enough to make fragmentation less of an issue.
typeof null should return the string
'null' and not
Second, the global object (
window in browsers) shouldn’t be in the scope chain of variables. But it is also much too late to change that now. At least, one won’t be in global scope in modules and
let never creates properties of the global object, not even when used in global scope.
ECMAScript 6 does introduce a few minor breaking changes (nothing you’re likely to encounter). They are listed in two annexes:
 The original 1JS proposal (warning: out of date): “ES6 doesn’t need opt-in” by David Herman.