JS Strict Mode
JS Strict Mode
JS Strict Mode
See transitioning to strict mode, if you want to change your code to work
in the restricted variant of JavaScript.
Sometimes, you'll see the default, non-strict, mode referred to as "sloppy
mode". This isn't an official term, but be aware of it, just in case.
Invoking strict mode
Strict mode applies to entire scripts or to individual functions. It doesn't
apply to block statements enclosed in {} braces; attempting to apply it to
such contexts does nothing. eval code, Function code, event handler
attributes, strings passed to WindowTimers.setTimeout(), and the like
are entire scripts, and invoking strict mode in them works as expected.
'use strict';
// Assuming a global variable
mistypedVariable exists
mistypeVariable = 17; // this line throws a ReferenceError due
to the
// misspelling of variable
Second, strict mode makes assignments which would otherwise silently
fail to throw an exception. For example, NaN is a non-writable global
variable. In normal code assigning to NaN does nothing; the developer
receives no failure feedback. In strict mode assigning to NaN throws an
exception. Any assignment that silently fails in normal code (assignment
to a non-writable global or property, assignment to a getter-only
property, assignment to a new property on a non-extensible object) will
throw in strict mode:
'use strict';
'use strict';
delete Object.prototype; // throws a TypeError
Fourth, strict mode prior to Gecko 34 requires that all properties named
in an object literal be unique. Normal code may duplicate property
names, with the last one determining the property's value. But since only
the last one does anything, the duplication is simply a vector for bugs, if
the code is modified to change the property value other than by changing
the last instance. Duplicate property names are a syntax error in strict
mode:
This is no longer the case in ECMAScript 2015 (bug 1041128).
'use strict';
var o = { p: 1, p: 2 }; // !!! syntax error
Fifth, strict mode requires that function parameter names be unique. In
normal code the last duplicated argument hides previous identically-
named arguments. Those previous arguments remain available
through arguments[i], so they're not completely inaccessible. Still, this
hiding makes little sense and is probably undesirable (it might hide a
typo, for example), so in strict mode duplicate argument names are a
syntax error:
function sum(a, a, c) { // !!! syntax error
'use strict';
return a + b + c; // wrong if this code ran
}
Sixth, strict mode in ECMAScript 5 forbids octal syntax. Octal syntax isn't
part of ECMAScript 5, but it's supported in all browsers by prefixing the
octal number with a zero: 0644 === 420 and "\045" === "%". In
ECMAScript 2015 Octal number is supported by prefixing a number with
"0o". i.e.
var a = 0o10; // ES2015: Octal
Novice developers sometimes believe a leading zero prefix has no
semantic meaning, so they use it as an alignment device but this
changes the number's meaning! The leading zero syntax for octals is
rarely useful and can be mistakenly used, so strict mode makes it a syntax
error:
'use strict';
var sum = 015 + // !!! syntax error
197 +
142;
})();
var x;
delete x; // !!! syntax error
"Securing" JavaScript
Strict mode makes it easier to write "secure" JavaScript. Some websites
now provide ways for users to write JavaScript which will be run by the
website on behalf of other users. JavaScript in browsers can access the
user's private information, so such JavaScript must be partially
transformed before it is run, to censor access to forbidden functionality.
JavaScript's flexibility makes it effectively impossible to do this without
many runtime checks. Certain language functions are so pervasive that
performing runtime checks has considerable performance cost. A few
strict mode tweaks, plus requiring that user-submitted JavaScript be strict
mode code and that it be invoked in a certain manner, substantially
reduce the need for those runtime checks.
First, the value passed as this to a function in strict mode is not forced
into being an object (a.k.a. "boxed"). For a normal function, this is always
an object: either the provided object if called with an object-valued this;
the value, boxed, if called with a Boolean, string, or number this; or the
global object if called with an undefined or null this. (Use call, apply,
or bind to specify a particular this.) Not only is automatic boxing a
performance cost, but exposing the global object in browsers is a security
hazard, because the global object provides access to functionality that
"secure" JavaScript environments must restrict. Thus for a strict mode
function, the specified this is not boxed into an object, and if
unspecified, this will be undefined:
'use strict';
function fun() { return this; }
console.assert(fun() === undefined);
console.assert(fun.call(2) === 2);
console.assert(fun.apply(null) === null);
console.assert(fun.call(undefined) === undefined);
console.assert(fun.bind(true)() === true);
That means, among other things, that in browsers it's no longer possible
to reference the window object through this inside a strict mode
function.
Second, in strict mode it's no longer possible to "walk" the JavaScript stack
via commonly-implemented extensions to ECMAScript. In normal code
with these extensions, when a function fun is in the middle of being
called, fun.caller is the function that most recently called fun,
and fun.arguments is the arguments for that invocation of fun. Both
extensions are problematic for "secure" JavaScript, because they allow
"secured" code to access "privileged" functions and their (potentially
unsecured) arguments. If fun is in strict mode,
both fun.caller and fun.arguments are non-deletable properties which
throw when set or retrieved:
function restricted() {
'use strict';
restricted.caller; // throws a TypeError
restricted.arguments; // throws a TypeError
}
function privilegedInvoker() {
return restricted();
}
privilegedInvoker();
Third, arguments for strict mode functions no longer provide access to
the corresponding function call's variables. In some old ECMAScript
implementations arguments.callerwas an object whose properties
aliased variables in that function. This is a security hazard because it
breaks the ability to hide privileged values via function abstraction; it also
precludes most optimizations. For these reasons no recent browsers
implement it. Yet because of its historical
functionality, arguments.caller for a strict mode function is also a non-
deletable property which throws when set or retrieved:
'use strict';
function fun(a, b) {
'use strict';
var v = 12;
return arguments.caller; // throws a TypeError
}
fun(1, 2); // doesn't expose v (or a or b)