本文已参与「新人创作礼」活动,一起开启掘金创作之路
早期的 JavaScript 语言有很多设计不合理的地方,但是为了兼容以前的代码,又不能改变老的语法,只能不断添加新的语法,引导程序员使用新语法。
严格模式对正常的 JavaScript 语义做了一些更改。
- 严格模式通过抛出错误来消除了一些原有静默错误。保证代码运行的安全。
- 严格模式修复了一些导致 JavaScript 引擎难以执行优化的缺陷:有时候,相同的代码,严格模式可以比非严格模式下运行得更快。
- 严格模式禁用了在 ECMAScript 的未来版本中可能会定义的一些语法,为未来新版本的 JavaScript 语法做好铺垫。
用法:
(1) 整个脚本文件
use strict放在脚本文件的第一行,整个脚本都将以严格模式运行。如果这行语句不在第一行就无效,整个脚本会以正常模式运行。(严格地说,只要前面不是产生实际运行结果的语句,use strict可以不在第一行,比如直接跟在一个空的分号后面,或者跟在注释后面。)
<script>
'use strict';
console.log('这是严格模式');
</script>
<script>
console.log('这是正常模式');
'use strict' // 写在这里无效
</script>
(2)单个函数
use strict放在函数体的第一行,则整个函数以严格模式运行。
function strict() {
'use strict';
return '这是严格模式';
}
function strict2() {
'use strict';
function f() {
return '这也是严格模式';
}
return f();
}
function notStrict() {
return '这是正常模式';
}
In strict mode, starting with ES2015, functions inside blocks are scoped to that block. Prior to ES2015, block-level functions were forbidden in strict mode.
在严格模式下,从ES2015开始,块内的函数作用于该块。在ES2015之前,块级函数在严格模式下是被禁止的。
ES6的模块化默认开启模块化
function strict() {
// because this is a module, I'm strict by default
}
export default strict;
所有class都默认开启严格模式
All parts of ECMAScript classes are strict mode code, including both class declarations and class expressions — and so also including all parts of class bodies.
严格模式与正常模式的不同
1、变量名直接赋值报错,正常模式是添加到window
'use strict';
let mistypeVariable;
mistypeVarible = 17; // Assuming no global variable mistypeVarible exists
// this line throws a ReferenceError due to the
// misspelling of "mistypeVariable" (lack of an "a")
2、只读属性不可写
'use strict';
'abc'.length = 5;
// TypeError: Cannot assign to read only property 'length' of string 'abc'
上面代码报错,因为length是只读属性,严格模式下不可写。正常模式下,改变length属性是无效的,但不会报错。
3、严格模式下,对只读属性赋值,或者删除不可配置(non-configurable)属性都会报错。对一个只有取值器(getter)、没有存值器(setter)的属性赋值,会报错。对禁止扩展的对象添加新属性,会报错。
// Assignment to a non-writable property
var obj1 = {};
Object.defineProperty(obj1, 'x', { value: 42, writable: false });
obj1.x = 9; // throws a TypeError
// 删除不可配置的属性会报错
'use strict';
var obj = Object.defineProperty({}, 'p', {
value: 1,
configurable: false
});
delete obj.p
// TypeError: Cannot delete property 'p' of #<Object>
// 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
4、严格模式下,形参名重复将报错。正常模式下,如果函数有多个重名的参数,前面重名的会被覆盖,但是可以用arguments[i]读取。严格模式下,这属于语法错误。
function sum(a, a, c) { // !!! syntax error
'use strict';
return a + a + c; // wrong if this code ran
}
You cannot write a
"use strict";directive in the body of a function definition that accepts rest, default, or destructured parameters. Doing so will throw a syntax error.
严格模式下还不允许使用默认参数,rest参数,解构参数。假如使用会报语法错误。
5、ECMAScript 5的严格模式禁止以0开头的八进制文字或八进制转义序列。在严格模式之外,以0开头的数字,如果所有数字都小于8,如0644,被解释为八进制数字(0644==420)。八进制转义序列,如"\45",等于"%",可以用来用八进制的扩展ASCII字符编码数字表示字符。在严格模式下,这是一个语法错误。在ECMAScript 2015中,通过在数字前加 "0o "来支持八进制字数;例如:
var a = 0o10; // ES2015: Octal
(function () {
'use strict'
console.log('\45')
console.log(045)
// Uncaught SyntaxError: Octal escape sequences are not allowed in strict mode.
}())
初学者可能不知道数字以0开头代表8进制,为了避免使用错误,严格模式不允许0开头的数字代表8进制。
'use strict';
var sum = 015 + // !!! syntax error
197 +
142;
var sumWithOctal = 0o10 + 8;
console.log(sumWithOctal); // 16
6、 strict mode in ECMAScript 2015 forbids setting properties on primitive values. Without strict mode, setting properties is ignored (no-op), with strict mode, however, a TypeError is thrown.
(function() {
'use strict';
false.true = ''; // TypeError
(14).sailing = 'home'; // TypeError
'with'.you = 'far away'; // TypeError
})();
In ECMAScript 5 strict-mode code, duplicate property names were considered a
SyntaxError. With the introduction of computed property names, making duplication possible at runtime, ECMAScript 2015 removed that restriction.
以下这段代码在ES6不报错,ES5及以前会报错
'use strict';
var o = { p: 1, p: 2 }; // syntax error prior to ECMAScript 2015
7、禁止使用with语句
'use strict';
var x = 17;
with (obj) { // !!! syntax error
// If this weren't strict mode, would this be var x, or
// would it instead be obj.x? It's impossible in general
// to say without running the code, so the name can't be
// optimized.
x;
}
8、正常模式下,JavaScript 语言有两种变量作用域(scope):全局作用域和函数作用域。严格模式创设了第三种作用域:eval作用域。
正常模式下,eval语句的作用域,取决于它处于全局作用域,还是函数作用域,有点类似花括号 {},使用let申明则是块级作用域,var则是全局。严格模式下,eval语句本身就是一个作用域,不再能够在其所运行的作用域创设新的变量了,也就是说,eval所生成的变量只能用于eval内部。
(function () {
'use strict';
var x = 2;
console.log(eval('var x = 5; x')) // 5
console.log(x) // 2
})()
var x = 17;
var evalX = eval("'use strict'; var x = 42; x;");
console.assert(x === 17); // true
console.assert(evalX === 42); // true
下面的例子说明了哪些eval开启了严格模式
function strict1(str) {
'use strict';
return eval(str); // str will be treated as strict mode code
}
function strict2(f, str) {
'use strict';
return f(str); // not eval(...): str is strict if and only
// if it invokes strict mode
}
function nonstrict(str) {
return eval(str); // str is strict if and only
// if it invokes strict mode
}
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!'");
9、严格模式删除(delete)变量或者删除对象的不可配置的属性(即:configurable: false)时报错,正常模式不报错但是删除不成功。
'use strict';
var x;
delete x; // !!! syntax error
eval('var y; delete y;'); // !!! syntax error
var obj = Object.create(null, {
x: {
value: 1,
configurable: false // true则可以删除和重新配置(writable,configurable,enumerable...)
}
});
delete obj.x; // TypeError: Cannot delete property 'x' of [object Object]
10、严格模式简化了eval和arguments
eval和arguments不能作为变量名和参数名,下面这些都是语法错误
'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;");
变量arguments代表函数的参数。严格模式下,函数内部改变参数与arguments的联系被切断了,两者不再存在联动关系。
function f(a) {
a = 2;
return [a, arguments[0]];
}
f(1); // 正常模式为[2, 2]
function f(a) {
'use strict';
a = 2;
return [a, arguments[0]];
}
f(1); // 严格模式为[2, 1]
上面代码中,改变函数的参数,不会反应到arguments对象上来。反之亦然
禁止使用arguments.callee,正常模式下调用指向的的是执行的函数,不会报错。严格模式明确规定,函数内部使用arguments.callee将会报错。并且arguments.callee是一个不可删除属性。
'use strict';
var f = function () {
return arguments.callee;
};
f(); // 报错
11、传递给非严格模式下函数中this的值会被强制转换为Object类型,严格模式下this不会转换为对象,假如是null就是null,undefined就是undefined,不会自动指向window。建议直接看英文。英文不好看例子更简单。
The value passed as
thisto a function in strict mode is not forced into being an object (a.k.a. "boxed"). For a normal function,thisis always an object: either the provided object if called with an object-valuedthis; the value, boxed, if called with a Boolean, string, or numberthis; or the global object if called with anundefinedornullthis. (Usecall,apply, orbindto specify a particularthis.) 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 specifiedthisis not boxed into an object, and if unspecified,thiswill beundefined:
'use strict';
function fun() { return this; }
console.assert(fun() === undefined); // true
console.assert(fun.call(2) === 2); // true
console.assert(fun.apply(null) === null); // true
console.assert(fun.call(undefined) === undefined); // true
console.assert(fun.bind(true)() === true); // true
12、函数内部不得使用fn.caller、fn.arguments,否则会报错。这意味着不能在函数内部得到调用栈了。
function restricted() {
'use strict';
restricted.caller; // throws a TypeError
restricted.arguments; // throws a TypeError
}
function privilegedInvoker() {
return restricted();
}
privilegedInvoker();
13、ES5严格模式下的函数申明不在作用域顶级会报错,ES6则不会
这一点要深究的话看这 es6.ruanyifeng.com/#docs/let,在…
'use strict';
if (true) {
function f() { } // !!! ES5 syntax error,ES6正常
f();
}
for (var i = 0; i < 5; i++) {
function f2() { } // !!! ES5 syntax error,ES6正常
f2();
}
function baz() { // kosher(合法的)
function eit() { } // also kosher
}