Apply your JS skills to key Mozilla projects as an MDN Fellow! http://mzl.la/MDNFellowship

mozilla

Revision 542685 of Strict mode

  • Revision slug: JavaScript/Strict_mode
  • Revision title: Strict mode
  • Revision id: 542685
  • Created:
  • Creator: endlesswind
  • Is current revision? No
  • Comment

Revision Content

{{ js_minversion_header("1.8.5") }}

        ECMAScript 5的严格模式是Javascript中的一种限制性更强的变种方式。严格模式不是一个子集:它在语义上与正常代码有着特意的差异。不支持严格模式的浏览器与同支持严格模式的浏览器行为上也不一样, 所以不要在未经严格模式特性测试情况下使用严格模式。严格模式可以与非严格模式共存,所以脚本可以逐渐的选择性加入严格模式。

        严格模式在语义上与正常的JavaSript有一些变化。 首先,严格模式通过将JavaScript陷阱变成错误的形式消除了。其次,严格模式修正了一些引擎难以优化 的错误:同样的代码有些时候严格模式会比非严格模式下更快。 (Firefox 4 未对其优化,但以后的版本会加入)。 最后,禁止了一些有可能在未来版本中定义的语法。

开启严格模式

严格模式可以应用到整个script标签或某个别函数。不要在封闭大括弧( {} )内这样做;尝试应用到这种情景下是没有任何效果的。 eval 代码,Function 代码, event handler attributes, strings passed to setTimeout, and the like are entire scripts, and invoking strict mode in them works as expected.

为某个script标签开启严格模式

        为整个script标签开启严格模式, 需要在所有语句之前放一个特定语句 "use strict"; (或 'use strict';)

// 整个语句都开启严格模式的语法
"use strict";
var v = "Hi!  I'm a strict mode script!";

这种语法存在陷阱,有一个大型网站已经被它坑倒了:不能盲目的拼合非冲突代码。考虑串联一个严格模式的脚本和一个非严格模式的脚本:整个拼合后的脚本代码变成了严格模式。反之亦然:非严格加严格为非严格。拼合全为严格模式的脚本或全为非严格模式的都没问题,仅当来严格模式与非严格模式有可能有问题。这里建议按一个个函数去开启严格模式(至少在过渡期要这样).

你也可以将整个脚本的内容用包裹在一个函数里面,并在外部函数中使用严格模式。This eliminates the concatenation problem but it means that you have to explicitly export any global variables out of the function scope.

为某个函数开启严格模式

同样的,各某个函数开启严格模式就放一句 "use strict"; (或 'use strict';) 在函数体所有语句之前。

function strict()
{
  // 函数级别严格模式语法
  'use strict';
  function nested() { return "And so am I!"; }
  return "Hi!  I'm a strict mode function!  " + nested();
}
function notStrict() { return "I'm not strict."; }

严格模式有哪些不同

严格模式同时改变了语法及运行时行为。变化通常有这几类:changes converting mistakes into errors (as syntax errors or at runtime), changes simplifying how the particular variable for a given use of a name is computed, changes simplifying eval and arguments, changes making it easier to write "secure" JavaScript, and changes anticipating future ECMAScript evolution.

Converting mistakes into errors

在严格模式下, 先前被接受的失误将会被认为是错误. JavaScript被设计为能使新人开发者更易于上手, 所以有时候会给本来错误操作赋予新的不报错误的语义(non-error semantics). 有时候这可以解决当前的问题, 但有时候却会给以后留下更大的问题. 严格模式则把这些失误当成错误, 以便可以发现并立即将其改正.

首先,严格模式下无法再意外创建全局变量。在普通的JavaScript里面给一个拼写错误的变量名赋值会使全局对象新增一个属性并继续“工作”(仅管后面可能出错:在现在的JavaScript中有可能)。严格模式中意外创建全局变量被抛出错误替代:

"use strict";
mistypedVariable = 17; // 抛出 ReferenceError

Second, strict mode makes assignments which would otherwise silently fail 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 property, assignment to a getter-only property, assignment to a new property on a non-extensible object) will throw in strict mode:

"use strict";

// Assignment to a non-writable property
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // throws a TypeError

// Assignment to a getter-only property
var obj2 = { get x() { return 17; } };
obj2.x = 5; // throws a TypeError

// Assignment to a new property on a non-extensible object
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // throws a TypeError

Third, strict mode makes attempts to delete undeletable properties throw (where before the attempt would simply have no effect):

"use strict";
delete Object.prototype; // throws a TypeError

Fourth, strict mode 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:

"use strict";
var o = { p: 1, p: 2 }; // !!! syntax error

Fifth, strict mode requires that function argument 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 forbids octal syntax. Octal syntax isn't part of ECMAScript, but it's supported in all browsers by prefixing the octal number with a zero: 0644 === 420 and "\045" === "%". 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! Octal syntax is rarely useful and can be mistakenly used, so strict mode makes octal a syntax error:

"use strict";
var sum = 015 + // !!! syntax error
          197 +
          142;

Simplifying variable uses

Strict mode simplifies how variable names map to particular variable definitions in the code. Many compiler optimizations rely on the ability to say that variable X is stored in that location: this is critical to fully optimizing JavaScript code. JavaScript sometimes makes this basic mapping of name to variable definition in the code impossible to perform until runtime. Strict mode removes most cases where this happens, so the compiler can better optimize strict mode code.

First, strict mode prohibits with. The problem with with is that any name inside the block might map either to a property of the object passed to it, or to a variable in surrounding (or even global) scope, at runtime: it's impossible to know which beforehand. Strict mode makes with a syntax error, so there's no chance for a name in a with to refer to an unknown location at runtime:

"use strict";
var x = 17;
with (obj) // !!! 语法错误
{
  // 如果没有开启严格模式,with中的这个x会指向with上面的那个x,还是obj.x?如果不运行代码,我们无法知道,因此,这种代码让引擎无法进行优化,速度也就会很慢了.
  x;
}

The simple alternative of assigning the object to a short name variable, then accessing the corresponding property on that variable, stands ready to replace with.

Second, eval of strict mode code does not introduce new variables into the surrounding scope. In normal code eval("var x;") introduces a variable x into the surrounding function or the global scope. This means that, in general, in a function containing a call to eval every name not referring to an argument or local variable must be mapped to a particular definition at runtime (because that eval might have introduced a new variable that would hide the outer variable). In strict mode eval creates variables only for the code being evaluated, so eval can't affect whether a name refers to an outer variable or some local variable:

var x = 17;
var evalX = eval("'use strict'; var x = 42; x");
assert(x === 17);
assert(evalX === 42);

Relatedly, if the function eval is invoked by an expression of the form eval(...) in strict mode code, the code will be evaluated as strict mode code. The code may explicitly invoke strict mode, but it's unnecessary to do so.

function strict1(str)
{
  "use strict";
  return eval(str); // str中包含的代码肯定会在严格模式下运行
}
function strict2(f, str)
{
  "use strict";
  return f(str); // f是个处于严格模式下的函数,或者f为eval且str中的适当位置处添加了"use strict"的情况下,str中的代码才会在严格模式下运行
}
function nonstrict(str)
{
  return eval(str); // 只有在str中的适当位置处添加了"use strict",str中的代码才会在严格模式下运行
}
strict1("'Strict mode code!'");
strict1("'use strict'; 'Strict mode code!'");
strict2(eval, "'Non-strict code.'");
strict2(eval, "'use strict'; 'Strict mode code!'");
nonstrict("'Non-strict code.'");
nonstrict("'use strict'; 'Strict mode code!'");

Thus names in strict mode eval code behave identically to names in strict mode code not being evaluated as the result of eval.

Third, strict mode forbids deleting plain names. delete name in strict mode is a syntax error:

"use strict";
eval("var x; delete x;"); // !!! syntax error

eval和arguments变的简单

Strict mode makes arguments and eval less bizarrely magical. Both involve a considerable amount of magical behavior in normal code: eval to add or remove bindings and to change binding values, and arguments by its indexed properties aliasing named arguments. Strict mode makes great strides toward treating eval and arguments as keywords, although full fixes will not come until a future edition of ECMAScript.

First, the names eval and arguments can't be bound or assigned in language syntax. All these attempts to do so are syntax errors:

"use strict";
eval = 17;
arguments++;
++eval;
var obj = { set p(arguments) { } };
var eval;
try { } catch (arguments) { }
function x(eval) { }
function arguments() { }
var y = function eval() { };
var f = new Function("arguments", "'use strict'; return 17;");

Second, strict mode code doesn't alias properties of arguments objects created within it. In normal code within a function whose first argument is arg, setting arg also sets arguments[0], and vice versa (unless no arguments were provided or arguments[0] is deleted). arguments objects for strict mode functions store the original arguments when the function was invoked. arguments[i] does not track the value of the corresponding named argument, nor does a named argument track the value in the corresponding arguments[i].

function f(a)
{
  "use strict";
  a = 42;
  return [a, arguments[0]];
}
var pair = f(17);
assert(pair[0] === 42);
assert(pair[1] === 17);

第三点,不再支持arguments.callee属性.在非严格模式中,arguments.callee指向当前正在执行的函数. This use case is weak: simply name the enclosing function! Moreover, arguments.callee substantially hinders optimizations like inlining functions, because it must be made possible to provide a reference to the un-inlined function if arguments.callee is accessed. arguments.callee for strict mode functions is a non-deletable property which throws when set or retrieved:

"use strict";
var f = function() { return arguments.callee; };
f(); // throws a TypeError

"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 isn't boxed into an object. For a normal function, this is always an object: 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.) Automatic boxing is a performance cost, but exposing the global object in browsers is a security hazard, because the global object provides access to functionality "secure" JavaScript environments must restrict. Thus for a strict mode function, the specified this is used unchanged:

"use strict";
function fun() { return this; }
assert(fun() === undefined);
assert(fun.call(2) === 2);
assert(fun.apply(null) === null);
assert(fun.call(undefined) === undefined);
assert(fun.bind(true)() === true);

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.caller was 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)

Paving the way for future ECMAScript versions

Future ECMAScript versions will likely introduce new syntax, and strict mode in ECMAScript 5 applies some restrictions to ease the transition. It will be easier to make some changes if the foundations of those changes are prohibited in strict mode.

First, in strict mode a short list of identifiers become reserved keywords. These words are implements, interface, let, package, private, protected, public, static, and yield. In strict mode, then, you can't name or use variables or arguments with these names.

function package(protected) // !!!
{
  "use strict";
  var implements; // !!!

  interface: // !!!
  while (true)
  {
    break interface; // !!!
  }

  function private() { } // !!!
}
function fun(static) { 'use strict'; } // !!!

Two Mozilla-specific caveats: First, if your code is JavaScript 1.7 or greater (you're chrome code, or you've used the right <script type="">) and is strict mode code, let and yield have the functionality they've had since those keywords were first introduced. But strict mode code on the web, loaded with <script src=""> or <script>...</script>, won't be able to use let/yield as identifiers. Second, while ES5 unconditionally reserves the words class, enum, export, extends, import, and super, before Firefox 5 Mozilla reserved them only in strict mode.

Second, strict mode prohibits function statements not at the top level of a script or function. In normal code in browsers, function statements are permitted "everywhere". This is not part of ES5 (or even ES3)! It's an extension with incompatible semantics in different browsers. Future ECMAScript editions will hopefully specify new semantics for function statements not at the top level of a script or function. Prohibiting such function statements in strict mode "clears the deck" for specification in a future ECMAScript release:

"use strict";
if (true)
{
  function f() { } // !!! syntax error
  f();
}
for (var i = 0; i < 5; i++)
{
  function f2() { } // !!! syntax error
  f2();
}
function baz() // kosher
{
  function eit() { } // also kosher
}

This prohibition isn't strict mode proper, because such function statements are an extension of basic ES5. But it is the recommendation of the ECMAScript committee, and browsers will implement it.

Strict mode in browsers

Browsers don't reliably implement strict mode yet, so don't blindly depend on it. Strict mode changes semantics. Relying on those changes will cause mistakes and errors in browsers which don't implement strict mode. Exercise caution in using strict mode, and back up reliance on strict mode with feature tests that check whether relevant parts of strict mode are implemented. Finally, make sure to test your code in browsers that do and don't support strict mode. If you test only in browsers that don't support strict mode, you're very likely to have problems in browsers that do, and vice versa.

相关链接

Revision Source

<p>{{ js_minversion_header("1.8.5") }}</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<a class="external" href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript 5</a>的严格模式是Javascript中的一种限制性更强的变种方式。严格模式不是一个子集:它在语义上与正常代码有着特意的差异。不支持严格模式的浏览器与同支持严格模式的浏览器行为上也不一样, 所以不要在未经严格模式特性测试情况下使用严格模式。严格模式可以与非严格模式共存,所以脚本可以逐渐的选择性加入严格模式。</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 严格模式在语义上与正常的JavaSript有一些变化。 首先,严格模式通过将JavaScript陷阱变成错误的形式消除了。其次,严格模式修正了一些引擎难以优化 的错误:同样的代码有些时候严格模式会比非严格模式下更快。 (Firefox 4 未对其优化,但以后的版本会加入)。 最后,禁止了一些有可能在未来版本中定义的语法。</p>
<h2 id=".E5.BC.80.E5.90.AF.E4.B8.A5.E6.A0.BC.E6.A8.A1.E5.BC.8F" style="position: static; z-index: auto;">开启严格模式</h2>
<p>严格模式可以应用到整个script标签或某个别函数。不要在封闭大括弧(<span style="line-height: 1.5;">&nbsp;</span><code style="font-size: 14px;">{} )内这样做;尝试应用到</code><span style="line-height: 1.5;">这种情景下是没有任何效果的。&nbsp;</span><code style="font-size: 14px;">eval</code><span style="line-height: 1.5;"> 代码,</span><code style="font-size: 14px;">Function</code><span style="line-height: 1.5;">&nbsp;代码, event handler attributes, strings passed to </span><a href="/zh-CN/DOM/window.setTimeout" style="line-height: 1.5;" title="zh-CN/DOM/window.setTimeout"><code>setTimeout</code></a><span style="line-height: 1.5;">, and the like are entire scripts, and invoking strict mode in them works as expected.</span></p>
<h3 id=".E4.B8.BA.E6.9F.90.E4.B8.AAscript.E6.A0.87.E7.AD.BE.E5.BC.80.E5.90.AF.E4.B8.A5.E6.A0.BC.E6.A8.A1.E5.BC.8F">为某个script标签开启严格模式</h3>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 为整个script标签开启严格模式, 需要在所有语句之前放一个特定语句&nbsp;<code>"use strict";</code>&nbsp;(或 <code>'use strict';)</code></p>
<pre class="brush: js">
// 整个语句都开启严格模式的语法
"use strict";
var v = "Hi!  I'm a strict mode script!";
</pre>
<p>这种语法存在陷阱,有一个<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=627531">大型网站</a>已经被它<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=579119">坑倒</a>了:不能盲目的拼合非冲突代码。考虑串联一个严格模式的脚本和一个非严格模式的脚本:整个拼合后的脚本代码变成了严格模式。反之亦然:非严格加严格为非严格。拼合全为严格模式的脚本或全为非严格模式的都没问题,仅当来严格模式与非严格模式有可能有问题。这里建议按一个个函数去开启严格模式(至少在过渡期要这样).</p>
<p>你也可以将整个脚本的内容用包裹在一个函数里面,并在外部函数中使用严格模式。This eliminates the concatenation problem but it means that you have to explicitly export any global variables out of the function scope.</p>
<h3 id=".E4.B8.BA.E6.9F.90.E4.B8.AA.E5.87.BD.E6.95.B0.E5.BC.80.E5.90.AF.E4.B8.A5.E6.A0.BC.E6.A8.A1.E5.BC.8F">为某个函数开启严格模式</h3>
<p>同样的,各某个函数开启严格模式就放一句&nbsp;<code>"use strict";</code> (或&nbsp;<code>'use strict';</code>) 在函数体所有语句之前。</p>
<pre class="brush: js">
function strict()
{
  // 函数级别严格模式语法
  'use strict';
  function nested() { return "And so am I!"; }
  return "Hi!  I'm a strict mode function!  " + nested();
}
function notStrict() { return "I'm not strict."; }
</pre>
<h2 id=".E4.B8.A5.E6.A0.BC.E6.A8.A1.E5.BC.8F.E6.9C.89.E5.93.AA.E4.BA.9B.E4.B8.8D.E5.90.8C">严格模式有哪些不同</h2>
<p>严格模式同时改变了语法及运行时行为。变化通常有这几类:changes converting mistakes into errors (as syntax errors or at runtime), changes simplifying how the particular variable for a given use of a name is computed, changes simplifying <code>eval</code> and <code>arguments</code>, changes making it easier to write "secure" JavaScript, and changes anticipating future ECMAScript evolution.</p>
<h3 id="Converting_mistakes_into_errors" style="position: static; z-index: auto;">Converting mistakes into errors</h3>
<p>在严格模式下, 先前被接受的失误将会被认为是错误. JavaScript被设计为能使新人开发者更易于上手, 所以有时候会给本来错误操作赋予新的不报错误的语义(non-error semantics). 有时候这可以解决当前的问题, 但有时候却会给以后留下更大的问题. 严格模式则把这些失误当成错误, 以便可以发现并立即将其改正.</p>
<p>首先,严格模式下无法再意外创建全局变量。在普通的JavaScript里面给一个拼写错误的变量名赋值会使全局对象新增一个属性并继续“工作”(仅管后面可能出错:在现在的JavaScript中有可能)。严格模式中意外创建全局变量被抛出错误替代:</p>
<pre class="brush: js">
"use strict";
mistypedVariable = 17; // 抛出 ReferenceError
</pre>
<p>Second, strict mode makes assignments which would otherwise silently fail throw an exception. For example, <code>NaN</code> is a non-writable global variable. In normal code assigning to <code>NaN</code> does nothing; the developer receives no failure feedback. In strict mode assigning to <code>NaN</code> throws an exception. Any assignment that silently fails in normal code (assignment to a non-writable property, assignment to a getter-only property, assignment to a new property on a <a href="/zh-CN/JavaScript/Reference/Global_Objects/Object/preventExtensions" title="zh-CN/JavaScript/Reference/Global Objects/Object/preventExtensions">non-extensible</a> object) will throw in strict mode:</p>
<pre class="brush: js">
"use strict";

// Assignment to a non-writable property
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // throws a TypeError

// Assignment to a getter-only property
var obj2 = { get x() { return 17; } };
obj2.x = 5; // throws a TypeError

// Assignment to a new property on a non-extensible object
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // throws a TypeError
</pre>
<p>Third, strict mode makes attempts to delete undeletable properties throw (where before the attempt would simply have no effect):</p>
<pre class="brush: js">
"use strict";
delete Object.prototype; // throws a TypeError
</pre>
<p>Fourth, strict mode 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:</p>
<pre class="brush: js">
"use strict";
var o = { p: 1, p: 2 }; // !!! syntax error
</pre>
<p>Fifth, strict mode requires that function argument names be unique. In normal code the last duplicated argument hides previous identically-named arguments. Those previous arguments remain available through <code>arguments[i]</code>, 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:</p>
<pre class="brush: js">
function sum(a, a, c) // !!! syntax error
{
  "use strict";
  return a + b + c; // wrong if this code ran
}
</pre>
<p>Sixth, strict mode forbids octal syntax. Octal syntax isn't part of ECMAScript, but it's supported in all browsers by prefixing the octal number with a zero: <code>0644 === 420</code> and <code>"\045" === "%"</code>. 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! Octal syntax is rarely useful and can be mistakenly used, so strict mode makes octal a syntax error:</p>
<pre class="brush: js">
"use strict";
var sum = 015 + // !!! syntax error
          197 +
          142;
</pre>
<h3 id="Simplifying_variable_uses">Simplifying variable uses</h3>
<p>Strict mode simplifies how variable names map to particular variable definitions in the code. Many compiler optimizations rely on the ability to say that variable <em>X</em> is stored in <em>that</em> location: this is critical to fully optimizing JavaScript code. JavaScript sometimes makes this basic mapping of name to variable definition in the code impossible to perform until runtime. Strict mode removes most cases where this happens, so the compiler can better optimize strict mode code.</p>
<p>First, strict mode prohibits <code>with</code>. The problem with <code>with</code> is that any name inside the block might map either to a property of the object passed to it, or to a variable in surrounding (or even global) scope, at runtime: it's impossible to know which beforehand. Strict mode makes <code>with</code> a syntax error, so there's no chance for a name in a <code>with</code> to refer to an unknown location at runtime:</p>
<pre class="brush: js">
"use strict";
var x = 17;
with (obj) // !!! 语法错误
{
  // 如果没有开启严格模式,with中的这个x会指向with上面的那个x,还是obj.x?如果不运行代码,我们无法知道,因此,这种代码让引擎无法进行优化,速度也就会很慢了.
  x;
}
</pre>
<p>The simple alternative of assigning the object to a short name variable, then accessing the corresponding property on that variable, stands ready to replace <code>with</code>.</p>
<p>Second, <a class="external" href="http://whereswalden.com/2011/01/10/new-es5-strict-mode-support-new-vars-created-by-strict-mode-eval-code-are-local-to-that-code-only/"><code>eval</code> of strict mode code does not introduce new variables into the surrounding scope</a>. In normal code <code>eval("var x;")</code> introduces a variable <code>x</code> into the surrounding function or the global scope. This means that, in general, in a function containing a call to <code>eval</code> every name not referring to an argument or local variable must be mapped to a particular definition at runtime (because that <code>eval</code> might have introduced a new variable that would hide the outer variable). In strict mode <code>eval</code> creates variables only for the code being evaluated, so <code>eval</code> can't affect whether a name refers to an outer variable or some local variable:</p>
<pre class="brush: js">
var x = 17;
var evalX = eval("'use strict'; var x = 42; x");
assert(x === 17);
assert(evalX === 42);
</pre>
<p>Relatedly, if the function <code>eval</code> is invoked by an expression of the form <code>eval(...)</code> in strict mode code, the code will be evaluated as strict mode code. The code may explicitly invoke strict mode, but it's unnecessary to do so.</p>
<pre class="brush: js">
function strict1(str)
{
  "use strict";
  return eval(str); // str中包含的代码肯定会在严格模式下运行
}
function strict2(f, str)
{
  "use strict";
  return f(str); // f是个处于严格模式下的函数,或者f为eval且str中的适当位置处添加了"use strict"的情况下,str中的代码才会在严格模式下运行
}
function nonstrict(str)
{
  return eval(str); // 只有在str中的适当位置处添加了"use strict",str中的代码才会在严格模式下运行
}
strict1("'Strict mode code!'");
strict1("'use strict'; 'Strict mode code!'");
strict2(eval, "'Non-strict code.'");
strict2(eval, "'use strict'; 'Strict mode code!'");
nonstrict("'Non-strict code.'");
nonstrict("'use strict'; 'Strict mode code!'");
</pre>
<p>Thus names in strict mode <code>eval</code> code behave identically to names in strict mode code not being evaluated as the result of <code>eval</code>.</p>
<p>Third, strict mode forbids deleting plain names. <code>delete name</code> in strict mode is a syntax error:</p>
<pre class="brush: js">
"use strict";
eval("var x; delete x;"); // !!! syntax error
</pre>
<h3 id=".E8.AE.A9eval.E5.92.8Carguments.E5.8F.98.E7.9A.84.E7.AE.80.E5.8D.95">让<code>eval和</code><code>arguments</code>变的简单</h3>
<p>Strict mode makes <code>arguments</code> and <code>eval</code> less bizarrely magical. Both involve a considerable amount of magical behavior in normal code: <code>eval</code> to add or remove bindings and to change binding values, and <code>arguments</code> by its indexed properties aliasing named arguments. Strict mode makes great strides toward treating <code>eval</code> and <code>arguments</code> as keywords, although full fixes will not come until a future edition of ECMAScript.</p>
<p>First, the names <code>eval</code> and <code>arguments</code> can't be bound or assigned in language syntax. All these attempts to do so are syntax errors:</p>
<pre class="brush: js">
"use strict";
eval = 17;
arguments++;
++eval;
var obj = { set p(arguments) { } };
var eval;
try { } catch (arguments) { }
function x(eval) { }
function arguments() { }
var y = function eval() { };
var f = new Function("arguments", "'use strict'; return 17;");
</pre>
<p>Second, strict mode code doesn't alias properties of <code>arguments</code> objects created within it. In normal code within a function whose first argument is <code>arg</code>, setting <code>arg</code> also sets <code>arguments[0]</code>, and vice versa (unless no arguments were provided or <code>arguments[0]</code> is deleted). <code>arguments</code> objects for strict mode functions store the original arguments when the function was invoked. <code>arguments[i]</code> does not track the value of the corresponding named argument, nor does a named argument track the value in the corresponding <code>arguments[i]</code>.</p>
<pre class="brush: js">
function f(a)
{
  "use strict";
  a = 42;
  return [a, arguments[0]];
}
var pair = f(17);
assert(pair[0] === 42);
assert(pair[1] === 17);
</pre>
<p>第三点,不再支持<code>arguments.callee</code>属性.在非严格模式中,<code>arguments.callee指向当前正在执行的函数</code>. This use case is weak: simply name the enclosing function! Moreover, <code>arguments.callee</code> substantially hinders optimizations like inlining functions, because it must be made possible to provide a reference to the un-inlined function if <code>arguments.callee</code> is accessed. <code>arguments.callee</code> for strict mode functions is a non-deletable property which throws when set or retrieved:</p>
<pre class="brush: js">
"use strict";
var f = function() { return arguments.callee; };
f(); // throws a TypeError
</pre>
<h3 id=".22Securing.22_JavaScript" style="position: static; z-index: auto;">"Securing" JavaScript</h3>
<p>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 <em>on behalf of other users</em>. 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.</p>
<p>First, the value passed as <code>this</code> to a function in strict mode isn't boxed into an object. For a normal function, <code>this</code> is always an object: the provided object if called with an object-valued <code>this</code>; the value, boxed, if called with a Boolean, string, or number <code>this</code>; or the global object if called with an <code>undefined</code> or <code>null</code> <code>this</code>. (Use <a href="/zh-CN/JavaScript/Reference/Global_Objects/Function/call" title="zh-CN/JavaScript/Reference/Global_Objects/Function/call"><code>call</code></a>, <a href="/zh-CN/JavaScript/Reference/Global_Objects/Function/apply" title="zh-CN/JavaScript/Reference/Global_Objects/Function/apply"><code>apply</code></a>, or <a href="/zh-CN/JavaScript/Reference/Global_Objects/Function/bind" title="zh-CN/JavaScript/Reference/Global_Objects/Function/bind"><code>bind</code></a> to specify a particular <code>this</code>.) Automatic boxing is a performance cost, but exposing the global object in browsers is a security hazard, because the global object provides access to functionality "secure" JavaScript environments must restrict. Thus for a strict mode function, the specified <code>this</code> is used unchanged:</p>
<pre class="brush: js">
"use strict";
function fun() { return this; }
assert(fun() === undefined);
assert(fun.call(2) === 2);
assert(fun.apply(null) === null);
assert(fun.call(undefined) === undefined);
assert(fun.bind(true)() === true);
</pre>
<p>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 <code>fun</code> is in the middle of being called, <code>fun.caller</code> is the function that most recently called <code>fun</code>, and <code>fun.arguments</code> is the <code>arguments</code> for that invocation of <code>fun</code>. Both extensions are problematic for "secure" JavaScript, because they allow "secured" code to access "privileged" functions and their (potentially unsecured) arguments. If <code>fun</code> is in strict mode, both <code>fun.caller</code> and <code>fun.arguments</code> are non-deletable properties which throw when set or retrieved:</p>
<pre class="brush: js">
function restricted()
{
  "use strict";
  restricted.caller;    // throws a TypeError
  restricted.arguments; // throws a TypeError
}
function privilegedInvoker()
{
  return restricted();
}
privilegedInvoker();
</pre>
<p>Third, <code>arguments</code> for strict mode functions no longer provide access to the corresponding function call's variables. In some old ECMAScript implementations <code>arguments.caller</code> was an object whose properties aliased variables in that function. This is a <a class="external" href="http://stuff.mit.edu/iap/2008/facebook/">security hazard</a> 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, <code>arguments.caller</code> for a strict mode function is also a non-deletable property which throws when set or retrieved:</p>
<pre class="brush: js">
"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)
</pre>
<h3 id="Paving_the_way_for_future_ECMAScript_versions" style="position: relative; z-index: 0;">Paving the way for future ECMAScript versions</h3>
<p>Future ECMAScript versions will likely introduce new syntax, and strict mode in ECMAScript 5 applies some restrictions to ease the transition. It will be easier to make some changes if the foundations of those changes are prohibited in strict mode.</p>
<p>First, in strict mode a short list of identifiers become reserved keywords. These words are <code>implements</code>, <code>interface</code>, <code>let</code>, <code>package</code>, <code>private</code>, <code>protected</code>, <code>public</code>, <code>static</code>, and <code>yield</code>. In strict mode, then, you can't name or use variables or arguments with these names.</p>
<pre class="brush: js">
function package(protected) // !!!
{
  "use strict";
  var implements; // !!!

  interface: // !!!
  while (true)
  {
    break interface; // !!!
  }

  function private() { } // !!!
}
function fun(static) { 'use strict'; } // !!!

</pre>
<p>Two Mozilla-specific caveats: First, if your code is JavaScript 1.7 or greater (you're chrome code, or you've used the right <code>&lt;script type=""&gt;</code>) and is strict mode code, <code>let</code> and <code>yield</code> have the functionality they've had since those keywords were first introduced. But strict mode code on the web, loaded with <code>&lt;script src=""&gt;</code> or <code>&lt;script&gt;...&lt;/script&gt;</code>, won't be able to use <code>let</code>/<code>yield</code> as identifiers. Second, while ES5 unconditionally reserves the words <code>class</code>, <code>enum</code>, <code>export</code>, <code>extends</code>, <code>import</code>, and <code>super</code>, before Firefox 5 Mozilla reserved them only in strict mode.</p>
<p>Second, <a class="external" href="http://whereswalden.com/2011/01/24/new-es5-strict-mode-requirement-function-statements-not-at-top-level-of-a-program-or-function-are-prohibited/">strict mode prohibits function statements not at the top level of a script or function</a>. In normal code in browsers, function statements are permitted "everywhere". <em>This is not part of ES5 (or even ES3)!</em> It's an extension with incompatible semantics in different browsers. Future ECMAScript editions will hopefully specify new semantics for function statements not at the top level of a script or function. <a class="external" href="http://wiki.ecmascript.org/doku.php?id=conventions:no_non_standard_strict_decls">Prohibiting such function statements in strict mode</a> "clears the deck" for specification in a future ECMAScript release:</p>
<pre class="brush: js">
"use strict";
if (true)
{
  function f() { } // !!! syntax error
  f();
}
for (var i = 0; i &lt; 5; i++)
{
  function f2() { } // !!! syntax error
  f2();
}
function baz() // kosher
{
  function eit() { } // also kosher
}
</pre>
<p>This prohibition isn't strict mode proper, because such function statements are an extension of basic ES5. But it is the recommendation of the ECMAScript committee, and browsers will implement it.</p>
<h2 id="Strict_mode_in_browsers" style="position: static; z-index: auto;">Strict mode in browsers</h2>
<p>Browsers don't reliably implement strict mode yet, so don't blindly depend on it. <em>Strict mode changes semantics.</em> Relying on those changes will cause mistakes and errors in browsers which don't implement strict mode. Exercise caution in using strict mode, and back up reliance on strict mode with feature tests that check whether relevant parts of strict mode are implemented. Finally, make sure to <em>test your code in browsers that do and don't support strict mode</em>. If you test only in browsers that don't support strict mode, you're very likely to have problems in browsers that do, and vice versa.</p>
<h2 id=".E7.9B.B8.E5.85.B3.E9.93.BE.E6.8E.A5">相关链接</h2>
<ul>
 <li><a class="external" href="http://whereswalden.com/2010/09/08/new-es5-strict-mode-support-now-with-poison-pills/" title="http://whereswalden.com/2010/09/08/new-es5-strict-mode-support-now-with-poison-pills/">Where's Walden? » New ES5 strict mode support: now with poison pills!</a></li>
 <li><a class="external" href="http://whereswalden.com/2011/01/24/new-es5-strict-mode-requirement-function-statements-not-at-top-level-of-a-program-or-function-are-prohibited/" title="http://whereswalden.com/2011/01/24/new-es5-strict-mode-requirement-function-statements-not-at-top-level-of-a-program-or-function-are-prohibited/">Where's Walden? » New ES5 strict mode requirement: function statements not at top level of a program or function are prohibited</a></li>
 <li><a class="external" href="http://whereswalden.com/2011/01/10/new-es5-strict-mode-support-new-vars-created-by-strict-mode-eval-code-are-local-to-that-code-only/" title="http://whereswalden.com/2011/01/10/new-es5-strict-mode-support-new-vars-created-by-strict-mode-eval-code-are-local-to-that-code-only/">Where's Walden? » New ES5 strict mode support: new vars created by strict mode eval code are local to that code only</a></li>
 <li><a class="external" href="http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/" title="http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/">John Resig - ECMAScript 5 Strict Mode, JSON, and More</a></li>
 <li><a class="external" href="http://dmitrysoshnikov.com/ecmascript/es5-chapter-2-strict-mode/">ECMA-262-5 in detail. Chapter 2. Strict Mode.</a></li>
 <li><a class="external" href="http://kangax.github.com/es5-compat-table/strict-mode/">Strict mode compatibility table</a></li>
</ul>
Revert to this revision