In the previous blog post I explained that you should normally use an Immediately-Invoked Function Expression (IIFE) to give variables function scope. That works fine as log as we remember to declare our variables using the var keyword. However when we forget the var keyword we are back to the original problem as the variables are added to the global scope.
Leaking undeclared variables
As you can see in the two code snippets below the text variables are not declared using var. Even though they are only used inside a function they are still added to the global scope. The end result is that the variables are added to the window object and the second scripts overwrites the variable from the first script. And JavaScript being really relaxed doesn’t really case about missing var keywords, it will just do its thing, however wrong the result may be
1: (function() {
2: text = "Hello from script 1";
3:
4: setTimeout(function () {
5: console.log(text);
6: }, 1000);
7: }());
8:
1: (function() {
2: text = "Hello from script 2";
3:
4: setTimeout(function () {
5: console.log(text);
6: }, 1000);
7: }());
These two scripts result in the following output:
Running JavaScript in strict mode
Fortunately there is a way that the JavaScript runtime can help us prevent this. The way to do that is by adding the string ‘use strict’ to our code. This might seem a bit strange as it is just a string. The reason for this is that it was added in ECMAScript 5 and doing it this way doesn’t cause an error in older browsers. All they see is a string that is not assigned to a variable. Not very useful but not an error either.
Just like variables ‘use strict’ is scoped to a function. So adding it applies it to that function and all nested ones. You could also add it outside of a function scope but that would change the default for all JavaScript executed in that window. This is because it changes the global scope and all other functions are defines as children of that global scope. In all likelihood you will be using some third party library and you cannot really know if all of them are compatible with ‘use strict’ so never go and change the global scope.
Adding ‘use strict’ to the IIFE in script2.js produces the following result. As you can see it only affects script2.js and that now throws and error about the missing var statement while script1.js runs unaffected.
1: (function () {
2: 'use strict';
3: text = "Hello from script 2";
4:
5: setTimeout(function () {
6: console.log(text);
7: }, 1000);
8: }());
Other effects of ‘use strict’
In this case I am mostly concerned about using ‘use strict’ to find missing variable declaration it actually does more than just that. It will disable a number of potential dangerous JavaScript features. One of the other things it disables is using the call stack from a JavaScript function. See this article for more information.
The drawback of ‘use strict’
While I would live to recommend that you always use ‘use strict’ it turns out there are a few potential issues. While ‘use strict’ is scoped the function and nested functions it turn out it also affects non nested functions that might be called. I mentioned the fact that walking the call stack is disabled. However the way this is done is not consistent between browsers and can result in unexpected results. Take the following program:
1: (function() {
2: function printCaller() {
3: var fn = arguments.callee;
4: while (fn) {
5: console.log(fn.toString().split("\n")[0]);
6: fn = fn.caller;
7: }
8: }
9:
10: function doMoreWork() {
11: printCaller();
12: }
13:
14: function doWork() {
15: 'use strict';
16:
17: doMoreWork();
18: console.log("All done");
19: }
20:
21: doWork();
22: }());
The doWork() function enables ‘use strict’ and calls doMoreWork() which calls printCaller(). Neither of the last two run with ‘use strict’.
When run in Chrome this produces the following result:
With FireFox we see the following:
And with Internet Explorer 11 we get the following:
Both IE and FireFox throw a runtime error when trying to read doWork() but Chrome just returns a null so the code doesn’t throw an error and continues.
The reason this turns out to be an issue for some people is that the Microsoft AJAX libraries contain similar stack walking code that starts failing on FireFox and IE as soon as you enable ‘use strict’. I am sure there are similar problems with other libraries but this is one Microsoft developers frequently run into if they are still using the AJAX libraries.
Conclusion
Use ‘use strict’ wherever you can but be aware of the differences in browser implementations that can trip you up.