什么是严格模式
严格模式"use strict";
是ES5
新增的语法,在不支持严格模式的浏览器中,这行代码仅会被识别为一个“字面量表达式语句”,而在支持严格模式的浏览器中,这行代码表示在对应作用域内开启严格模式。
为什么要使用严格模式
启用严格模式后后,JavaScript引擎会对代码进行更加严格的评估,对之前较为宽松的、静默处理的、难以优化的代码进行语法检查,以便于开发人员在编写代码的过程中实时分析,并显示语法和代码的质量问题。
在何处使用"use strict";
在显式使用式"use strict";
时,由于"use strict";
可以作用到所以在位置的整个作用域,所以式"use strict";
应用在某个作用域开始位置即可,即:
1.全局代码的开始处加入
2.在eval代码开始处加入
3.在函数声明语句开始处加入
4.在new Function()所传入的函数体开始处加入
除此之外,还有一些情况下默认使用严格模式,如:
1.ES6模块中
2.ES6的类声明和类表达式的整个声明中(包含extends关键字后边的表达式)
3.在引擎或宿主的运行参数中指定,如node --use_strict
语法限制
在严格模式中,有7种
语法被禁用。
在对象字面量声明中存在相同的属性名
此语法限制是在
ES5
中规定的,但ES6
就取消了,所以最后一个声明项总是有效的,只在不支持ES6
的浏览器中会报错
"use strict";
var obj = {
name: "Lily",
name: "Wango"
}
// IE11中报错: strict 模式下不允许一个属性有多个定义
在函数声明中,参数具有相同标识符
在非严格模式中,总是后一个同名参数生效(前一个被覆盖)
"use strict";
function foo(a, a, b) {}
// SyntaxError: Duplicate parameter name not allowed in this context
// 非严格模式
function foo(a, a, c, b, b, c) {
console.log(a + c);
}
// 参数的个数不会因为重名而改变,写了多少就是多少
console.log(foo.length);
// 6
// 重复变量都是最后一个声明生效,覆盖了前者
foo(1, 2, 3, 4, 5, 6);
// 8
// 在这里传三个实参,第二个c的值为undefined,2 + undefined得到NaN
foo(1, 2, 3);
// NaN
不能声明、重写或删除eval
和arguments
"use strict";
// 不能重新赋值,不能重新声明(变量声明和函数声明都不允许)
eval = function() {};
// SyntaxError: Unexpected eval or arguments in strict mode
var arguments;
// SyntaxError: Unexpected eval or arguments in strict mode
function arguments(){}
// SyntaxError: Unexpected eval or arguments in strict mode
// 不能作为形参标识符
function foo(eval) {}
// SyntaxError: Unexpected eval or arguments in strict mode
// 不能作为catch子句的异常对象名
try{} catch(arguments) {}
// SyntaxError: Unexpected eval or arguments in strict mode
// 不能删除
delete eval;
// Delete of an unqualified identifier in strict mode.
delete arguments;
// Delete of an unqualified identifier in strict mode.
而在非严格模式中以上语法都是有效的
用0
前缀声明八进制字面量
"use strict";
var num = 012;
// SyntaxError: Octal literals are not allowed in strict mode.
console.log(num);
在非严格模式下以上代码输出10
用delete
删除显式声明的标识符、名称或具名函数
"use strict";
var a;
delete a;
// Delete of an unqualified identifier in strict mode.
function foo(){}
delete foo;
// Delete of an unqualified identifier in strict mode.
function foo(a) {
delete a;
// Delete of an unqualified identifier in strict mode.
}
try{}catch(err){ delete err}
// Delete of an unqualified identifier in strict mode.
在非严格模式中,以上操作无效,但不会抛出错误
使用保留字
"use strict";
function interface() {}
// SyntaxError: Unexpected strict mode reserved word
包含with
语句
在严格模式中,with
直接被禁止了
"use strict";
with(window) {}
// SyntaxError: Strict mode code may not include a with statement
执行限制
对未声明的标识符赋值
在非严格模式中,对未声明的标识符赋值时,会在全局对象上创建该标识符并完成运算,而在严格模式下,这种行为将导致ReferenceError
。
"use strict";
a = 10;
// ReferenceError: a is not defined
// 非严格模式
a = 10;
console.log(window.a);
// 10
对不可操作的内容进行操作
"use strict";
var obj = {
name: 'Wango'
}
Object.preventExtensions(obj);
obj.age = 24;
// TypeError: Cannot add property age, object is not extensible
Object.seal(obj);
delete obj.name;
// TypeError: Cannot delete property 'name' of #<Object>
delete Function.prototype;
// TypeError: Cannot delete property 'prototype' of function Function() { [native code] }
Object.defineProperty(obj, 'age', {
writable: false,
value: 24
});
obj.age = 25;
// TypeError: Cannot assign to read only property 'age' of object '#<Object>'
非严格模式下忽略、无效、静默处理
访问arguments.callee
或函数的caller
属性
"use strict";
function foo() {
console.log(foo.caller);
// TypeError: 'caller', 'callee', and 'arguments' properties
// may not be accessed on strict mode functions or the
// arguments objects for calls to them
}
foo();
造成这个问题的是.
语法存取属性,而不是属性本身,所以以下代码在严格模式下也是能执行的:
"use strict";
function foo() {
console.log('callee' in arguments);
// true
console.log('caller' in foo);
// true
}
foo();
arguments
与参数的不同表现
在非严格模式中,arguments
的数据和参数的数据是相互绑定的,可以看作是指向同一片内存空间,一个改变,另一个会一起改变
function foo(a, b) {
console.log(a, b);
// A B
arguments[0] = 10;
console.log(a, b);
// 10 B
b = 20;
console.log(arguments);
// [10, 20]
}
foo('A', 'B');
而在严格模式中,arguments
与参数的修改将不再相互影响
"use strict";
function foo(a, b) {
console.log(a, b);
// A B
arguments[0] = 10;
console.log(a, b);
// A B
b = 20;
console.log(arguments);
// [10, B]
}
foo('A', 'B');
严格模式的范围
除非在启动JavaScript引擎时将其设置为严格模式,或者通过ES6
模块加载整个系统,否在指定一个有限的严格模式。
"use strict";
只能用于作用域的起始位置,在此代码前有任何代码都会导致严格模式失效,就算仅有一个;
。
// 严格模式失效
;"use strict";
var eval;
在函数作用域中,严格模式能作用于函数中的代码,同样也能作用于函数本身
function eval() {
// SyntaxError: Unexpected eval or arguments in strict mode
"use strict";
}
// 严格模式外的代码不受影响
var arguments;
参考资料:
《JavaScript语言精髓与编程实践(第3版)》(周爱民/著)