It’s time to start using JavaScript strict mode
ECMAScript 5 introduced strict mode to JavaScript. The intent is to allow developers to opt-in to a “better” version of JavaScript, where some of the most common and egregious errors are handled differently. For a while, I was skeptical, especially with only one browser (Firefox) initially supporting strict mode. Fast forward to today, every major browser supports strict mode in their latest version, including Internet Explorer 10 and Opera 12. It’s time to start using strict mode.
What does it do?
Strict mode makes a lot of changes to how JavaScript runs, and I group these into two categories: obvious and subtle. The subtle changes aim to fix subtle problems, and I’m not going to delve into those here; if you’re interested in those details, please see Dmitry Soshnikov’s excellent, ECMA-262-5 in Detail. Chapter 2. Strict Mode[1]. I’m far more interested in talking about the obvious changes: the ones you should know about before using strict mode, and the ones that will most likely help you the most.
Before getting into specific features, keep in mind that one of the goals of strict mode is to allow for faster debugging of issues. The best way to help developers debug is to throw errors when certain patterns occur, rather than silently failing or behaving strangely (which JavaScript does today outside of strict mode). Strict mode code throws far more errors, and that’s a good thing, because it quickly calls to attention things that should be fixed immediately.
Eliminates with
To begin, strict mode eliminates the with statement. It is now considered invalid JavaScript syntax and will throw a syntax error when it appears in strict mode code. So first step to using strict mode: make sure you’re not using with.
// Causes a syntax error in strict mode
with (location) {
alert(href);
}
Prevents accidental globals
Next, variables must be declared before they can be assigned to. Without strict mode, assigning a value to an undeclared variable automatically creates a global variable with that name. This is one of the most common errors in JavaScript. In strict mode, attempting to do so throws an error.
// Throws an error in strict mode
(function() {
someUndeclaredVar = "foo";
}());
Eliminates this coercion
Another important change is a this-value of null or undefined is no longer coerced to the global. Instead, this remains its original value, and so may cause some code depending on the coercion to break. For example:
window.color = "red";
function sayColor() {
alert(this.color);
}
// Throws an error in strict mode, "red" otherwise
sayColor();
// Throws an error in strict mode, "red" otherwise
sayColor.call(null);
Basically, the this-value must be assigned a value or else it remains undefined. That means constructors accidentally called without new are also affected:
function Person(name) {
this.name = name;
}
// Error in strict mode
var me = Person("Nicholas");
In this code, this is undefined when the Person constructor is called without new. Since you can’t assign a property to undefined, this code throws an error. In non-strict mode, this would be coerced to the global and so name would be assigned as a global variable.
No duplicates
It can be quite easy to duplicate properties in objects or named arguments in functions if you’ve been doing a lot of coding. Strict mode throws an error when it comes across either pattern:
// Error in strict mode - duplicate arguments
function doSomething(value1, value2, value1) {
//code
}
// Error in strict mode - duplicate properties
var object = {
foo: "bar",
foo: "baz"
};
These are both syntax errors and so the error is thrown before the code is executed.
Safer eval()
Even though eval() wasn’t removed, it has undergone some changes in strict mode. The biggest change is that variables and functions declared inside of an eval() statement are no longer created in the containing scope. For example:
(function() {
eval("var x = 10;");
// Non-strict mode, alerts 10
// Strict mode, throws an error because x is undeclared
alert(x);
}());
Any variables or functions created inside of eval() stay inside of eval(). You can, however, return a value from eval() if you wish to pass a value back out:
(function() {
var result = eval("var x = 10, y = 20; x + y");
// Works in strict and non-strict mode (30)
alert(result);
}());
Errors for immutables
ECMAScript 5 also introduced the ability to modify property attributes, such as setting a property as read only or freezing an entire object’s structure. In non-strict mode, attempting to modify an immutable property fails silently. You’ve probably run into this issue with some native APIs. Strict mode ensures that an error is thrown whenever you try to modify an object or object property in a way that isn’t allowed.
var person = {};
Object.defineProperty(person, "name", {
writable: false,
value: "Nicholas"
});
// Fails silently in non-strict mode, throws error in strict mode
person.name = "John";
In this example, the name property is set to read only. In non-strict mode, assigning to name fails silently; in strict mode, an error is thrown.
Note: I very strongly encourage you to use strict mode if you’re using any of the ECMAScript attribute capabilities. If you’re changing the mutability of objects, you’ll run into a lot of errors that will fail silently in non-strict mode.
How do you use it?
Strict mode is very easily enabled in modern browsers using the following pragma:
"use strict";
Even though this looks like a string that isn’t assigned to a variable, it actually instructs conforming JavaScript engines to switch into strict mode (browsers that don’t support strict mode simply read this as an unassigned string and continue to work as usual). You can use it either globally or within a function. That being said, you should never use it globally. Using the pragma globally means that any code within the same file also runs in strict mode.
// Don't do this
"use strict";
function doSomething() {
// this runs in strict mode
}
function doSomethingElse() {
// so does this
}
This may not seem like a big deal, however, it can cause big problems in our world of aggressive script concatenation. All it takes is one script to include the pragma globally for every script its concatenated with to be switch into strict mode (potentially revealing errors you never would have anticipated).
For that reason, it’s best to only use strict mode inside of functions, such as:
function doSomething() {
"use strict";
// this runs in strict mode
}
function doSomethingElse() {
// this doesn't run in strict mode
}
If you want strict mode to apply to more than one function, use an immediately-invoked function expression (IIFE):
(function() {
"use strict";
function doSomething() {
// this runs in strict mode
}
function doSomethingElse() {
// so does this
}
}());
Conclusion
I strongly recommend everyone start using strict mode now. There are enough browsers supporting it that strict mode will legitimately help save you from errors you didn’t even know where in your code. Make sure you don’t include the pragma globally, but use IIFEs as frequently as you like to apply strict mode to as much code as possible. Initially, there will be errors you’ve never encountered before – this is normal. Make sure you do a fair amount of testing after switching to strict mode to make sure you’ve caught everything. Definitely don’t just throw "use strict" in your code and assume there are no errors. The bottom line is that it’s time to start using this incredibly useful language feature to write better code.
Update (14-Mar-2012): Added note about using strict mode pragma with non-conforming JavaScript engines.
Update (21-Mar-2012): Fixed typo.
References
- ECMA-262-5 in Detail. Chapter 2. Strict Mode by Dmitry Soshnikov
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.
Both comments and pings are currently closed.




23 Comments
Agreed that “use strict”; should never be applied globally, but please don’t blindly wrap everything in an IIFE without exposing the functions it contains for unit testing, when you can.
Eric Wendelin on March 13th, 2012 at 5:43 pm
Since integrating realtime JSHint into my editor, I absolutely love the immediate feedback I get and certainly notice lots less time wasted on stupid errors on my part.
Strict mode plays well to that, though I would add one thing..
There is no reason to ship “use strict” in your production code. There is no performance gain (verified with V8 team and Brendan a while ago) and I don’t need my users’ VMs doing the extra checks as well. Keep it development only, strip it out during build. This way you also avoid the concatenation issue you reference.
Paul Irish on March 13th, 2012 at 11:48 pm
Nice overview of common strict mode gotchas. Some more things to look out for:
Octal string escape sequences (e.g.
'\251'are disallowed in strict mode. Use hexadecimal escapes instead.Similarly, octal literals (e.g.
0123) aren’t valid numeric literals in strict mode, and using them will throw an error. Note that this also affects the grammar for unquoted property names:({ 0123: 45 })would throw an error in strict mode.Some future reserved words only apply in strict mode:
implements,interface,let,package,private,protected,public,static, andyield. Therefore, these are disallowed identifiers (variable names) in strict mode. Even though they aren’t reserved words,evalandargumentsare disallowed as variable names too in strict mode.Mathias Bynens on March 14th, 2012 at 1:40 am
There are a couple of gotchas.
Strict mode could still impact the future-proofness of your work.
Browsers are still implementing strict mode, potentially applying improvements with each release. E.g. a couple of months ago when iOS5 got released we suddenly found a couple of new strict mode related bugs in our regression tests on a project we worked on. Imagine that project would have been delivered a few weeks before that point in time, it would have caused a bug in a live environment. Bottom line, when using strict mode, developers should verify their syntax pro-actively.
Second there can be potential issues mixing strict mode and non-strict mode when concatenating files.
When using strict mode on a file level, appending a script that depends on non-strict-mode behavior to a strict-mode script can cause things to break. Like you wrote, you should never use it globally, however when using third party libraries you will need to check if strict mode has been applied on a file level before concatenating it.
Just some points to keep in mind.
Bobby van der Sluis on March 14th, 2012 at 6:20 am
IE 10? Well, everybody must be using that by now, yeah? [/sarcasm]
Honestly… a lot of us who develop/design for organizations that a.) have no control over the browsers their users choose/default to use and b.) have pages that absolutely must (for legal reasons) be visible and operable, all of this stuff just sounds like pipe dreams. The grass is indeed greener on your side of the fence–but we can’t jump over until IE10 somehow comes to Windows XP through automatic updates.
haliphax on March 14th, 2012 at 6:31 am
@haliphax: You’ll catch a bunch of errors when testing your code in browsers that support strict mode and older browsers can only benefit from that. Even if they don’t support the mode natively.
Ara Pehlivanian on March 14th, 2012 at 7:03 am
Nicholas,
I’d honestly be interested in reading your perspective on how this works in the context of the current browser landscape.
How do you use strict mode when you have to accommodate and test in browsers such as IE8 and 9?
Warren Parsons on March 14th, 2012 at 7:20 am
@Warren – strict mode is ignored in older browsers. That’s the benefit of having the pragma as a string – older browsers just interpret it as an unassigned string and go on their merry way.
Nicholas C. Zakas on March 14th, 2012 at 10:20 am
@haliphax – as Ara said, I’m not really sure what you’re arguing. Every browser supports strict mode, not just IE 10. You’ll catch more errors, which actually ensures your legal/professional obligations rather than hurting it. As I said, you shouldn’t just blindly switch into strict mode and assume everything will work, but using it will only improve the quality of your code, not hurt it.
Nicholas C. Zakas on March 14th, 2012 at 10:22 am
@Bobby – I see no evidence that using strict mode affects “future proofness”. In fact, using strict mode is often cited as the way to ensure future proofness since future versions of JavaScript will be based off of strict mode.
Nicholas C. Zakas on March 14th, 2012 at 10:31 am
@Paul – I disagree. There may not be a performance gain, but there’s also not a performance loss. In production, even more than in development, is where you want to be sure you’re noticing errors. Minimizing the changes between the development and production versions of the code is key to being able to debug issues quickly and efficiently. Yes it helps during development, but there’s no reason to pull it out of production code.
Nicholas C. Zakas on March 14th, 2012 at 10:33 am
@Nicholas
Thanks. I figured there was some obvious piece to the puzzle that I was missing.
It might be helpful to put a note about this in the article.
Warren Parsons on March 14th, 2012 at 10:42 am
Very good point, I can’t believe I forgot to do that initially.
Nicholas C. Zakas on March 14th, 2012 at 1:06 pm
Enjoyed reading, thanks.
Would you say it’s good to use the strict pragma during development, then remove it for production?
Francisc on March 14th, 2012 at 2:34 pm
I would leave it in all the time.
Nicholas C. Zakas on March 14th, 2012 at 2:40 pm
> Minimizing the changes between the development and production versions of the code is key to being able to debug issues quickly and efficiently
So you’re advocating against using uglify or closure compiler? Somewhat relatedly, I’m helping get some docs out about source maps soon that help solve the “debugging production” scenario.
If you’re interested in error *capture* then window.onerror and exception.stack are your answers (the latter added to webkit last month).
Paul Irish on March 14th, 2012 at 3:57 pm
I don’t recall mentioning minifiers at all, so please keep the discussion on point. I only advocate solutions that don’t disrupt control flow. I don’t like using Closure Compiler because I don’t like how it changes the code I write, same with Uglify. I stick with YUI Compressor because the code that goes out is the same as the code I wrote as far as flow goes.
The problem with flipping back is that you’re no longer testing what’s being delivered to production, and so you can’t be sure of how it will behave. If you’re delivering non-strict mode to production, then you should also have non-strict mode in development so you get the same experience; if you’re delivering strict mode to production, then you should also have strict mode in development. This is the primary rule of good development: you need to be actively using and testing what’s going out to production or else you can never be certain if production will be stable.
Using something like YUI Compressor doesn’t actually change the script aside from removing the unnecessary white space and comments. Fundamentally, it’s exactly the same (and if it’s not, YUI Compressor throws an error). And that’s what I want: the code I tested is now on production and functioning the same way. Anything less turns into a maintenance issue before long.
Nicholas C. Zakas on March 14th, 2012 at 5:14 pm
If turning off strict mode introduced bugs on production wouldn’t that already be the case in browsers where strict mode hasn’t been implemented.
So far I don’t really see the benefit of strict mode above what code quality tools like jslint can offer. Seems like just another way for your code to break without any real runtime benefits. See also Strict XHTML
Jethro Larson on March 14th, 2012 at 6:52 pm
I never said turning off strict mode would introduce bugs. My point is that you should be developing with the code you’re going to push out, plain and simple.
Strict mode catches more issues than JSLint/JSHint because some of them are runtime issues that wouldn’t show up in static analysis. If you switch to strict mode, you will find more errors at first, and that makes your code better in the future.
Nicholas C. Zakas on March 14th, 2012 at 7:00 pm
Testing strict mode on the QUnit project results in this error:
“‘caller’, ‘callee’, and ‘arguments’ properties may not be accessed on strict mode functions or the arguments objects for calls to them”
‘callee’ is used here, part of QUnit.equiv, for deep object comparisons: https://github.com/jquery/qunit/blob/d1880e31f6a76cc018a5cf8b1d066314ebcaecbe/qunit/qunit.js#L1260
Any suggestions on dealing with that?
Jörn Zaefferer on March 15th, 2012 at 12:59 am
To nit-pick, the already shipped Opera 11.60 has strict-mode support, as well as the yet-to-ship Opera 12.
Geoffrey Sneddon on March 15th, 2012 at 2:45 am
Object.defineProperty(person, "name" {
8th code sample is missing a comma between 2nd and 3rd argument. Great article.
Paolo Fragomeni on March 16th, 2012 at 11:56 am
- JavaScript was the only reliable cross-browser thing that worked.
Now that Gen 5 browsers have finally achieved some dom compatibility ground – something else needs to be broken.
-The “use strict”, is just another atempt to break the web!
And it will!
-Unless…
Troy III on March 24th, 2012 at 5:51 am
Comments are automatically closed after 14 days.