Strict Mode Is Coming To Town

By YUI TeamDecember 14th, 2010

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.

Specifying Strict Mode

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...
}());

Scope

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.

Implied Global Variables

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.

Global Leakage

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.

Noisy Failure

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.

Octal

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.

Et cetera

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.

It Is Still An Imperfect World

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.

Why Strict Mode Matters

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.

20 Comments

  1. 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

  2. If arguments.callee is out, is there another way of referencing a lambda from its body?

  3. Are there any browsers (beta or not) that are fully strict mode compliant?

  4. @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...
    };

  5. 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) }

  6. @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|

  7. @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)

  8. A great chart showing ES5 compatibility in various browsers can be found here: http://kangax.github.com/es5-compat-table/

  9. David-Sarah Hopwood said:
    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.

  10. 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:

    A function can’t have a variable with the same name as one of its parameters.

    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.

    A function can’t delete its own variables.

    It was always so — variables (except of those which created using eval context) always have {DontDelete} in ES3 / [[Configurable]] = false in ES5. I.e. it’s not possible to delete a variable regardless the strict mode.

    Dmitry.

  11. Will YUI3 add “use strict” to its modules?

  12. 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

  13. In strict mode, the method form binds this to the object as before. The function form binds this to undefined, not the global object.

  14. 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.

  15. Thanks Douglas.

  16. May want to correct typo in “Noisy Failure” section– “createProperty” should be “defineProperty”.

  17. franz enzenhofer said:
    January 13, 2011 at 5:34 am

    “strictly awesome”

  18. Crockford rockz!

  19. So, when will YUI Compressor stop dropping the “use strict”; pragma from the code during minifaction? :)

  20. s/minifaction/minification/