JavaScript中“use strict”的作用

原文:What Does “use strict” Do in JavaScript?

JavaScript的“use strict”会开启严格模式。本文解释了何为严格模式。

JavaScript的严格模式对于处理常见的错误更为严格。除非有足够的理由,否则最好开启严格模式。

要开启严格模式,在文件或函数以字符串'use strict'作为第一个表达式即可。

1
2
3
// 如果是一个 .js 文件, 可以在文件的开头写入'use strict'.
// 在 'use strict' 之前,可以写注释
'use strict';
1
2
3
4
function foo() {
'use strict';
// 即使 'foo' 外的代码不是严格模式,`foo()`函数体内的代码也是严格模式
}
1
2
3
var x = 1;
// 这里 **不会** 启用严格模式,因为上一条语句是文件的第一个表达式。
'use strict';

使用严格模式主要有几个好处:

未声明变量的引用错误

在非严格模式,以下代码隐式的创建了一个全局变量x。

1
2
3
4
5
6
function foo() {
x = 42;
}

foo();
x; // 42, `x` 现在是一个全局变量!

在严格模式下,在未使用letvar声明x时,设置x = 42会抛出错误:

1
2
3
4
5
6
7
'use strict';

function foo() {
x = 42; // ReferenceError: x is not defined
}

foo();

this默认指向undefined

在非严格模式下,调用一个未绑定任何对象的函数时,this会指向全局对象。是不是很违反直觉?

1
2
3
4
5
const foo = function() {
console.log(this); // Object [global] { ... }
};

foo();

严格模式下,this指向undefined

1
2
3
4
5
6
7
'use strict';

const foo = function() {
console.log(this); // undefined
};

foo();

强制只读属性

Object.freeze()函数可以使JavaScript对象成为不可变对象,对冻结的对象,不能添加、移除属性,也不能修改已有属性。

但是,Object.freeze()有个意想不到的问题:它只在严格模式下禁止修改对象,在非严格模式,修改一个冻结的对象,JavaScript运行时会允许操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const frozen = function() {
'use strict';
return Object.freeze({ answer: 42 });
};

const unstrict = function() {
const obj = frozen();
// 该函数是非严格模式,因此可以修改冻结对象
obj.answer = 43;
console.log(obj.answer);
};

const strict = function() {
'use strict';
const obj = frozen();
// TypeError: Cannot assign to read only property 'answer' of object '#<Object>'
obj.answer = 43;
};

unstrict();
strict();

不允许对原始类型设置属性

在非严格模式,对数值变量设置属性,会失败但不报错。

1
2
3
4
5
6
7
let answer = 42;

// 非严格模式失败不报错
answer.prop = 'test';

// undefined
console.log(answer.prop);

严格模式下,对数值变量设置属性,会抛出TypeError错误。

1
2
3
4
5
6
'use strict';

let answer = 42;

// TypeError: Cannot create property 'prop' on number '42'
answer.prop = 'test';

阻止删除prototype

非严格模式下,对不可删除的属性执行delete会失败但不报错:

1
2
3
4
5
// 非严格模式下失败不报错
delete Object.prototype;

const obj = { answer: 42 };
console.log(obj.constructor.prototype); // {}

在严格模式下,删除prototype抛出TypeError错误:

1
2
3
4
'use strict';

// TypeError: Cannot delete property 'prototype' of function Object() { [native code] }
delete Object.prototype;