Debug your site faster with ECMAScript Strict ModeBy Rajasekharan Vengalil ECMAScript, ratified for widespread adoption by Ecma International, is standardese for what much of the world knows as JavaScript. Strictly speaking (no pun on title intended), JavaScript and ECMAScript aren’t identical. JavaScript is a dialect of ECMAScript, but the differences are mostly negligible and largely exist for historical backward-compatibility reasons. ECMAScript 5, the latest version available, (henceforth referred to as ES5) brings a suite of interesting features to the table. Most of these new features are designed to bring greater programming discipline to the language. I’m going to focus on Strict Mode—one of the features that directly addresses some of the more notorious parts of the language. Essentially, it’s an entirely new execution mode for JavaScript that causes the execution engine to run code with slightly different semantics. What is strict mode?Strict Mode is a way to cause the runtime engine to interpret and execute JavaScript with different semantics than what you’d see with unrestricted code. Code running in strict mode has the following characteristics:
Applies to specific code units. You cannot apply Strict Mode to all your .js files in one shot (unless you concatenate all of them, in which case it’s one code unit as far as the runtime is concerned). The basic rationale behind Strict Mode is the introduction of some runtime-enforced discipline to JavaScript development. I have always felt that JavaScript is far too dynamic for its own good, and, in my opinion, strict mode addresses some of that excessive dynamism. When you mark a code segment as “strict,” Many of the tricky parts of JavaScript are enforced by the engine instead of requiring programmer discipline. Can you spot the bug in the following snippet? With Strict Mode on, the runtime will! Browser supportPretty much all of today’s modern browsers support Strict Mode in their JavaScript engines, including Internet Explorer, Chrome, Firefox, Safari, and Opera. On Internet Explorer (IE), Strict Mode is available from version 10 onward. You can download the latest platform preview of IE10 from IE Test Drive. All the samples in this article have been tested on IE10 platform preview using a JavaScript eval console I had put together a while ago. Selected samples have been tested on Chrome 14 and Firefox 7 Beta as well. Strict mode contextsRunning a piece of JavaScript under Strict Mode is simplicity itself. Here’s an example: The nice thing is that this is perfectly valid ECMAScript 3 code as well. (ES3 is the previous edition of ECMAScript. What happened to ES4? It went the way of the dodo!) An ES3 JavaScript engine will simply ignore the noop line and proceed with running the rest of the script. In fact, this sort of syntactic backward compatibility with ES3 has been a key design goal for ES5. A surprisingly large part of the ES5 specification can be implemented completely in ES3 JavaScript. Strict Mode, however, is an example of an ES5 feature that perhaps cannot be implemented purely in ES3 JavaScript without additional support from the runtime. The following kinds of JavaScript code can be made to run under Strict Mode: 1. Global codeThis is basically executable code that you enter inside a script tag. For example: Note that with HTML5, you no longer need to add the type attribute for script tags. 2. Eval codeEval code that has the Strict Mode directive prefix: Or is invoked from strict mode code: 3. Function codeFunctions that have the Strict Mode directive prefixed before the rest of the code (putting the directive anywhere else doesn’t count): Functions declared in Strict Mode code inherit the strictness: Note that the latter case is particularly relevant when you are defining callbacks for various event handlers. You should also note that strictness does not extend across call stacks. Here’s an example: Strict mode restrictionsSo what exactly are the restrictions and alternate semantics that apply in strict mode? Let’s review some of the key restrictions: 1. Identifiers must be declared before they can be assigned toThis aspect, in my opinion,makes Strict Modeworthwhile all on its own,even if there were nothing more to it. Undeclared variable assignments do not automatically get added as expando properties on the global object. With this in place, the following snippet that I’d given above under the “What is strict mode?” section will fail to run and throw a “ReferenceError” instead because of the typo in the variable name “product” in the assignment inside the “for” loop. 2. No automatic context for context-less function callsFunctions that are called without setting an explicit context do not automatically get the “global object” in “this”. Consider the following snippet: Here, “foo” is being invoked without setting an explicit context object, i.e., we are not calling it like this: In unrestricted mode this causes the context to be automatically initialized to the “global” object, which in browsers is the “window” object. Since the snippet above was running in unrestricted mode, the expression “this === window” evaluates to true. If we modify the function like so, however, we see that “this” is no longer equal to “window”: 3. Reserved keywords cannot be identifier namesNaming variables and functions as eval, arguments, implements, let, private, public, yield, interface, package, protected, and static will cause errors. 4. Violations of ES5 property configuration cause errorsViolations of the configuration as specified in the property descriptor for ES5 properties will cause errors to be thrown in Strict Mode instead of being silently ignored. Here are some examples: 1. Writing to a non-writable property: Note the line highlighted in bold. Setting the “writable” property descriptor to “false” makes the “name” property of the “person” object read-only. Attempts to assign to this property will be silently ignored in unrestricted mode but causes a “TypeError” to be thrown in Strict Mode. 2. Changing configuration of a non-configurable property: Here we attempted to change the property descriptor on a non-configurable object. Again, an error that would have gone unnoticed in unrestricted mode results in a “TypeError” being thrown in Strict Mode. 5. Writing to read-only accessor propertiesWriting to accessor properties that do not have a “setter” defined causes errors to be thrown instead of being silently ignored: Here, “name” is an accessor property that does not have a “setter” method defined. Attempts to assign a value to this property results in an error in Strict Mode while being quietly ignored in unrestricted mode. 6. Cannot extend non-extensible objectsExtending a non-extensible object throws an error in Strict Mode instead of being silently ignored: 7. Other sundry restrictionsThere are a few other restrictions for Strict Mode code that are used somewhat less frequently. Numeric constants are no longer interpreted as having an octal base if you put a leading zero. Variable/function instantiations in Strict Mode “eval” code occur in an environment that is local to the “eval” code and not in the environment of the calling code. This means that “eval” code cannot introduce new identifiers in the caller’s execution context/scope. “arguments” is immutable. You cannot arbitrarily extend the “arguments” object by tacking on your own properties to it. Now, why anyone would even want to do this is puzzling to me, but it must have been happening often enough for Ecma to make the effort to specify that you can’t do it in Strict Mode! “arguments.callee” and “arguments.caller” are not available in strict functions. I have to say, I’m not thrilled with this particular restriction! Creating duplicate property definitions on an object is not allowed in strict mode code. The following snippet, for instance, produces an error in Strict Mode: This code throws up a “SyntaxError” with the message, “Multiple definitions of a property not allowed in strict mode”. In unrestricted mode, “o.name” would have the value “bar”. Calling “delete” on an ES5 property that has its “configurable” property set to “false” results in an error being thrown in Strict Mode. This is a variation on the restriction discussed in point 4 above. The JavaScript “with” statement is not allowed in strict mode code. It is not allowed to create functions with duplicate parameter names in strict mode. Again, it defies logic as to why anyone would want to do this, but there it is! Tips and best practicesHere are a few things you should consider while writing code that uses Strict Mode:
Now, even if a major chunk of your end users are on browsers that don’t support Strict Mode, it still makes sense to use Strict Mode in your development environment because Strict Mode helps enforce JavaScript development best practices. At the very least, take advantage of automated enforcement when you develop! And of course, be sure that you test everything in unrestricted mode before going live. Enable strict mode in small increments instead of a one-shot quick fix. If you have a 3000-line JS file for instance, it’s probably not smart to simply add the "use strict"; directive at the top of the file—semantic differences between the two modes can potentially result in subtle unforeseen bugs. Do it in smaller chunks at a function level, and certainly use it with abandon for new code that you write. I encourage you to experiment with and read up on Strict Mode. In my opinion, this is one of the best features introduced as part of ES5. I think you’ll find the following resources incredibly useful:
About the AuthorRajasekharan Vengalil has been coding for more than 9 years and works as a Developer Evangelist at Microsoft. He has worked on a wide range of Microsoft products & technologies ranging from VC++, MFC and Win32 programming to the latest developments on the web front, JavaScript and .NET. His current focus is on advances in web development, HTML5 and building rich internet applications. Read his Nerdworks Blogorama here. |