This is the time and season when people all over the world forget their differences and come together in peace and fellowship to celebrate the first anniversary of the ECMA General Assembly’s approval of The ECMAScript Programming Language Standard, Fifth Edition. The most important feature in ES5 is the new Strict Mode. Strict Mode is an opt-in mode that repairs or removes some of the language’s most problematic features.
There are two ways to request strict mode. The first is to insert this pragma
"use strict";
at the top of a file or compilation unit. It must appear before any other statements, but it may be preceded by whitespace and comments. It has the form of a useless string literal statement, so it will be ignored by ES3 systems. This means that it is possible to write ES5/strict programs that can also run on the older browsers. Strict code can also interact with non-strict (or sloppy) code, so strict functions can call sloppy functions, and sloppy functions can call strict functions. This high level of compatibility makes adoption of strict mode easy.
All of the code in the file or compilation unit with the "use strict"; preamble will be processed as strict code. There is a problem, though. Performance considerations currently compel us to concatenate many JavaScript files together to avoid cumulative HTTP delays. If a file with a "use strict"; preamble has sloppy code appended to it, the sloppy code will be processed as strict and will probably fail. There is an easy rule: Do not mix strict and sloppy in the same file, but we have already seen some famous websites get this wrong.
The second way is to insert the pragma is as the first statement of a function. That declares that the whole function will be strict, including any functions that are nested within it. Strictness respects function scope, so strict code and sloppy code can be mixed in the same file. This second form works very well with the Module Pattern and its many variations. The second form is preferred because it avoids the concatenation hazard.
(function () {
"use strict";
// this function is strict...
}());
(function () {
// but this function is sloppy...
}());
Historically, JavaScript has been confused about how functions are scoped. Sometimes they seem to be statically scoped, but some features make them behave like they are dynamically scoped. This is confusing, making programs difficult to read and understand. Misunderstanding causes bugs. It also is a problem for performance. Static scoping would permit variable binding to happen at compile time, but the requirement for dynamic scope means the binding must be deferred to runtime, which comes with a significant performance penalty.
Strict mode requires that all variable binding be done statically. That means that the features that previously required dynamic binding must be eliminated or modified. Specifically, the with statement is eliminated, and the eval function’s ability to tamper with the environment of its caller is severely restricted.
One of the benefits of strict code is that tools like YUI Compressor can do a better job when processing it.
JavaScript has implied global variables. If you do not explicitly declare a variable, a global variable is implicitly declared for you. This makes programming easier for beginners because they can neglect some of their basic housekeeping chores. But it makes the management of larger programs much more difficult and it significantly degrades reliability. So in strict mode, implied global variables are no longer created. You should explicitly declare all of your variables.
There are a number of situations that could cause this to be bound to the global object. For example, if you forget to provide the new prefix when calling a constructor function, the constructor’s this will be bound unexpectedly to the global object, so instead of initializing a new object, it will instead be silently tampering with global variables. In these situations, strict mode will instead bind this to undefined, which will cause the constructor to throw an exception instead, allowing the error to be detected much sooner.
JavaScript has always had read-only properties, but you could not create them yourself until ES5’s Object.createProperty function exposed that capability. If you attempted to assign a value to a read-only property, it would fail silently. The assignment would not change the property’s value, but your program would proceed as though it had. This is an integrity hazard that can cause programs to go into an inconsistent state. In strict mode, attempting to change a read-only property will throw an exception.
The octal (or base 8) representation of numbers was extremely useful when doing machine-level programming on machines whose word sizes were a multiple of 3. You needed octal when working with the CDC 6600 mainframe, which had a word size of 60 bits. If you could read octal, you could look at a word as 20 digits. Two digits represented the op code, and one digit identified one of 8 registers. During the slow transition from machine codes to high level languages, it was thought to be useful to provide octal forms in programming languages.
In C, an extremely unfortunate representation of octalness was selected: Leading zero. So in C, 0100 means 64, not 100, and 08 is an error, not 8. Even more unfortunately, this anachronism has been copied into nearly all modern languages, including JavaScript, where it is only used to create errors. It has no other purpose. So in strict mode, octal forms are no longer allowed.
The arguments pseudo array becomes a little bit more array-like in ES5. In strict mode, it loses its callee and caller properties. This makes it possible to pass your arguments to untrusted code without giving up a lot of confidential context. Also, the arguments property of functions is eliminated.
In strict mode, duplicate keys in a function literal will produce a syntax error. A function can’t have two parameters with the same name. A function can’t have a variable with the same name as one of its parameters. A function can’t delete its own variables. An attempt to delete a non-configurable property now throws an exception. Primitive values are not implicitly wrapped.
If your program passes JSLint, it will probably work in strict mode.
There are still problems in JavaScript that strict mode does not address. For example, semicolon insertion is still a hazard, and 0.1 + 0.2 is still not equal to 0.3. Correction of these problems will have to wait for future editions.
In addition to the obvious benefits to program reliability and readability, strict mode is helping to solve the Mashup Problem. We want to be able to invite third party code onto our pages to do useful things for us and our users, without giving that code the license to take over the browser or to misrepresent itself to the user or our servers. We need to constrain the third party code. Systems like Google’s Caja do this, but at a significant cost in performance and inconvenience. My own ADsafe system also does this, but at the cost of eliminating this and [] subscripting from the language, which can make adoption difficult. Strict mode allows us to make third party code with the convenience and performance of ADsafe and the expressiveness of Caja. This will be critically important as our sites become more complex and more connected.
Strict mode does not solve the XSS problem. The solution to that problem depends on W3C taking some positive action.
ES5/strict is now in previews, and will soon be standard equipment in all standards compliant browsers everywhere.
December 14, 2010 at 6:46 pm
as usual awesome post! ES5 is the future..Object.create(), Object.defineProperty(), Object.isExtensible(), Array.isArray(), native support for JSON are great features..checking out ADsafe, looks promising
December 15, 2010 at 1:51 am
If arguments.callee is out, is there another way of referencing a lambda from its body?
December 15, 2010 at 8:20 am
Are there any browsers (beta or not) that are fully strict mode compliant?
December 15, 2010 at 9:15 am
@Arieh, yep -
var carl = function bob(a) {
if (!a) { bob(1); } // reference scoped to inside this function
alert(carl === bob); // gotcha - true in all browsers but false in ie...
};
December 15, 2010 at 10:38 am
Arieh: You can name function expressions and refer to them by that name. e.g.
var x = function lookMaNoYCombinator(a, b) { if (a === 0) return a + b; else return lookMaNoYCombinator(a - 1, b) }December 15, 2010 at 12:51 pm
@Arieh: you should be using a named lambda if you want to recurse. eg. (function f(){ f() }). This also has the advantage of not bindings the Arguments object to |this|
December 15, 2010 at 12:52 pm
@Nate: nightly builds of webkit and firefox should both be strict mode compliant, and we would all appreciate bugs being filed if you find any (at http://bugs.webkit.org and http://bugs.mozilla.org)
December 15, 2010 at 2:53 pm
A great chart showing ES5 compatibility in various browsers can be found here: http://kangax.github.com/es5-compat-table/
December 16, 2010 at 7:40 pm
‘with’ and injecting eval didn’t really implement dynamic binding. Even full ES3 uses lexical binding (although not necessarily static binding) in all cases. These features were certainly confusing, though.
December 17, 2010 at 2:46 am
Hello Douglas,
Good overview, thanks. In addition, I’m sure your readers will be interested in the detailed strict mode description: http://dmitrysoshnikov.com/ecmascript/es5-chapter-2-strict-mode/
P.S.: a pair of additions/corrections:
It’s OK to have a variable declaration with the same name as one of the arguments. Technically, declaration will be just skipped, since it’s already declared via the argument binding.
It was always so — variables (except of those which created using
evalcontext) always have {DontDelete} in ES3 / [[Configurable]] = false in ES5. I.e. it’s not possible to delete a variable regardless the strict mode.Dmitry.
December 17, 2010 at 9:18 am
Will YUI3 add “use strict” to its modules?
December 28, 2010 at 7:23 am
Hi Douglas,
I am confused on below statement from your post.
“Strict mode requires that all variable binding be done statically. That means that the features that previously required dynamic binding must be eliminated or modified”
keyword “this” – Does it have dynamic binding or lexical(static) binding?
If it is having dynamic binding, do you mean to say we should stop using ‘this’ in strict mode?
I am really confused. I started learning JavaScript from last one month from your video presentations. They are very very helpful. This is my first programming language. May be my doubt is very odd here.
But just want to hear from you on ‘this’ doubt.
Thanks
December 29, 2010 at 6:39 pm
In strict mode, the method form binds this to the object as before. The function form binds this to undefined, not the global object.
December 29, 2010 at 6:42 pm
Dmitry, you just described the case where you can make the variables that you can then delete! The syntax of the delete operator allows for variables exactly for that case. But no more.
And David-Sarah, the hairs you are splitting are quite short.
January 7, 2011 at 2:53 am
Thanks Douglas.
January 11, 2011 at 11:03 am
May want to correct typo in “Noisy Failure” section– “createProperty” should be “defineProperty”.
January 13, 2011 at 5:34 am
“strictly awesome”
January 20, 2011 at 4:26 pm
Crockford rockz!
February 3, 2011 at 7:09 am
So, when will YUI Compressor stop dropping the “use strict”; pragma from the code during minifaction? :)
February 3, 2011 at 7:09 am
s/minifaction/minification/