js严格模式详解

什么是严格模式

严格模式"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

不能声明、重写或删除evalarguments

"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版)》(周爱民/著)
原文地址:https://www.cnblogs.com/hycstar/p/14591035.html