Why Use Strict Directive
Why Use Strict Directive
Use It
Posted on http://cjihrig.com/blog/javascripts-strict-mode-and-why-you-should-use-it/
by Colin Ihrig.
Starting with ECMAScript 5, developers are able to place their code into a more constrained form
of execution known as strict mode. Strict mode improves JavaScript code by enforcing better
programming practices and eliminating some of the language’s insecure and ill-advised features.
Strict mode is enabled by adding the following directive to your code:
"use strict";
The “use strict”; directive can be used in two ways. The first method of invoking strict mode is at
the file level. By adding the directive at the beginning of a file (the directive may only be preceded
by comments and whitespace), strict mode is enabled in a global context. This means that all of
your code will be evaluated in strict mode. Caution must be taken when concatenating strict and
non-strict scripts together. Placing a strict script first will force the non-strict script to be evaluated
in strict mode. Placing a non-strict script first will cause the opposite behavior. This caused some
problems for Amazon.
The second way to enable strict mode is at the function level. To enable this level of strict mode,
place the “use strict”; directive at the beginning of the function body. As with global strict mode,
the directive may only be preceded by whitespace and comments. Using strict mode at the function
level allows a programmer to mix and match strict and non-strict functions in the same file. This is
useful when some legacy code relies on features that have been deprecated in strict mode. The
following example shows how strict and non-strict functions can coexist in a single file.
function foo() {
"use strict";
// this function is executed in strict mode
}
function bar() {
// this function is executed in non-strict mode
}
One of the nice things about strict mode is its backward compatibility. Older versions of JavaScript
will treat the “use strict”; directive as a meaningless string literal and ignore it. However, newer
versions of JavaScript will give the statement special treatment and switch to strict mode. For
browsers that support strict mode, the following restrictions apply.
x = 1;
y = 2;
z = x + y;
}
Notice that only the variables ‘x’ and ‘z’ are declared using the var keyword. There is a good
chance that the programmer also meant to declare ‘y’, but mistakenly did not. The code will
execute properly, but with the side effect of creating a global variable named ‘y’ with the value 2.
Since window is the global object, this is equivalent to writing:
window.y = 2;
This behavior can be problematic if ‘y’ is already defined elsewhere and is expected to have a
different value. This leads to code that doesn’t scale well and is difficult to debug. Enabling strict
mode will catch this problem. Instead of making ‘y’ a global variable, an exception will occur. The
exception shown in Chrome looks like this:
ReferenceError: y is not defined
In strict mode, the with statement has been completely disabled. Any attempt to use the with
statement will result in the following syntax error. Note: A much better idea is to assign the object
to a variable and access it’s properties via the variable.
SyntaxError: Strict mode code may not include a with statement
Identifier Naming
Strict mode places several naming restrictions on variables, functions, and parameters. The strings
‘eval’ and ‘arguments’ cannot be used as identifiers, nor can they have values assigned to them.
Because JavaScript has a built-in ‘eval’ function and ‘arguments’ object, this eliminates possible
confusion. Attempting to use ‘eval’ or ‘arguments’ as a name results in the following exception:
SyntaxError: Variable name may not be eval or arguments in strict mode
Additionally, identifiers can no longer use any of the following future reserved keywords:
• implements
• interface
• let
• package
• private
• protected
• public
• static
• yield
this Usage
Use of a ‘this’ variable is common in object-oriented programming. Inside a function, the ‘this’
variable points to the object that owns the function. However, when a function does not belong to
any specific object, the ‘this’ variable points to the global object (window). Strict mode removes
accidental or malicious access of the global object by assigning ‘this’ a value of undefined. If a
function is owned by an object, then ‘this’ still points to that object as expected. In the following
example, the function ‘foo’ returns undefined.
function foo() {
"use strict";
return this;
}
Read-only Properties
JavaScript allows developers to create read-only properties on objects. Attempts to write a new
value to a read-only property fail silently in non-strict code. In other words, the property’s value
remains unchanged, but the program does not provide any warning/error. In strict mode, such
behavior will cause the script to throw an exception. The following example creates a read-only
property named ‘prop1′. In strict mode, the subsequent assignment of ‘prop1′ causes a TypeError
exception.
function foo() {
"use strict";
var obj = Object.defineProperties({}, {
prop1 : {
value : 1,
writable : false
}
});
obj.prop1 = 2;
}
Object.preventExtensions(obj);
obj.prop2 = 2;
}
The object ‘obj’ is constructed with a single property, ‘prop1.’ When ‘Object.preventExtensions’ is
called, ‘obj’ becomes non-extensible. The attempt to add ‘prop2′ to the object results in the
following exception:
TypeError: Can't add property prop2, object is not extensible
Similarly, non-strict functions may have multiple parameters with the same name. In strict mode,
this is not allowed. In the following example, duplicating ‘param1′ causes a syntax error.
function foo(param1, param1) {
"use strict";
alert(param1);
}
eval Variables
Non-strict code can use the ‘eval’ function to add new variables to the surrounding scope. Prior to
native JSON support in browsers, ‘eval’ was commonly (and unsafely) used to construct objects
from strings. The constructed objects then became a part of the surrounding scope. In strict mode,
‘eval’ cannot introduce new variables. When executed in strict mode, the following piece of code
will not introduce the ‘bar’ variable into the surrounding scope. Note: if a function containing
‘eval’ is executed in strict mode, then the code inside the ‘eval’ function is also executed in strict
mode.
// while in strict mode
eval("var bar = 10;");
delete obj.prop2;
delete obj.prop1;
}
The delete operator is intended to work on object properties. Attempting to delete normal variables
and functions will result in a syntax error. All of the delete operations in the following example will
fail.
function foo(param1) {
"use strict";
var bar = 1;
function baz() {};
delete param1;
delete bar;
delete baz;
}
The ‘arguments’ object also contains a pointer to the function that is currently executing. The
current function is referred to as the callee, and can be referenced using ‘arguments.callee’. This
syntax is only useful inside an anonymous function, because anonymous functions do not have
names. In any other case, it makes more sense to refer to the callee by name. In strict mode, access
to ‘arguments.callee’ is not allowed.
A similar method can be used to determine where a function call was made from. An
‘arguments.caller’ object was available in older browsers, but has since been deprecated. However,
the calling method can still be determined using ‘arguments.callee.caller’. Strict mode also
prohibits access to the caller. In the following example, ‘bar’ is not in strict mode. However,
attempting to access ‘arguments.callee.caller’ will still fail because ‘foo’ is a strict mode function.
function foo() {
"use strict";
bar(1, 2);
}
UPDATE (11/21/14)
Enabling strict mode allows some JavaScript engines, such as v8, to optimize code that it otherwise
would not. In non-strict mode, referencing ‘arguments’ and a named argument in the same function
will cause v8 to not optimize the function. For a slightly more detailed read, see this issue and my
personal will-it-optimize project.
UPDATE (11/21/14)
I’d also like to thank Chris Dickinson for providing an excellent example of (what I feel are) bad
coding practices that strict mode prevents. The following example returns 102 in non-strict mode,
but throws an error in strict mode as one function tries to overwrite the arguments of another
function.
// "use strict"; // uncomment this line to see an error thrown
function modify() {
poison.arguments[0] = 100;
}
function poison(a, b) {
modify();
return a + b;
}
console.log(poison(1, 2));
Octals
Octal variables represent numbers in the base-8 number system. They are rarely used and have a
very confusing syntax. Positive octal numbers are prefixed with a ’0′ while negative octals begin
with ‘-0′. For example, declaring the octal number 100 looks like this:
var foo = 0100;
Since people tend to ignore leading zeros, this can easily be confused with the decimal value 100.
However, a quick call to ‘parseInt()’ shows that the octal value is actually equal to 64 when
converted to decimal. To resolve this problem, strict mode disallows the use of octals. Octal
variables and octal escape sequences are both treated as syntax errors in strict mode.