JavaScript 默认是非严格模式的,可以通过 "use strict";
启用严格模式。此声明语句可以放在 JS 文件顶部,也可以放在函数内部。
启用严格模式
1、外部脚本在 JS 文件开头声明,内部脚本在 <script>
标签开头声明,声明后所有 JS 代码启用严格模式:
"use strict";console.log('Hello World!');
错误写法:
console.log("test");"use strict"; // 置于代码之后的声明,严格模式不生效!
2、在函数内部声明函数启用严格模式,此时本函数体内部的 JS 代码将启用严格模式:
function strictFunc() {"use strict"; // 函数级严格模式 let x = 10; y = 20; // ReferenceError: y is not defined}function nonStrictFunc() { y = 20; // 非严格模式下隐式创建全局变量(不推荐)}
错误写法:
if (true) {"use strict"; // 无效!严格模式无法在块级作用域启用 x = 10; // 非严格模式下隐式创建全局变量}
3、模块化脚本(ES6 Modules)无需显式声明,默认启用严格模式:
// module.js(无需写"use strict")export default function() { x = 10; // ReferenceError: x is not defined}
4、类(ES6 Class)声明或类方法内部无需显式声明默认启用严格模式:
class MyClass { constructor() { x = 10; // ReferenceError: x is not defined }}
为何 JS 代码会有两种不同的解析结果?
这就不得不提到历史原因了,JS 之父创造 JavaScript 时,仅用了 10 天时间,这久导致了 JS 在后来使用中发现了一些问题,又由于浏览器的版本迭代必须要兼顾一些旧的代码(不可能浏览器来一个版本更新,直接把所有网站一棒打死),所以就有了 严格模式
的出现,这个模式的用途就是告诉浏览器,我这个网站的代码你按照严格模式
来解析,无需考虑历史兼容性,可能存在的隐式错误可以先告诉我。
严格模式 vs 非严格模式
主要区别如下:
变量声明
非严格模式:未声明的变量赋值会隐式创建全局变量。
严格模式:未声明的变量赋值会抛出 ReferenceError。
<script> function test1 () { y = 10; // 声明为全局变量 } test1(); console.log(y); // 10</script><script> function test2 () {"use strict"; x = 10; // ReferenceError: x is not defined } test2(); console.log(x); // test2 报错,此行代码不执行</script>
静默错误转显式错误
删除不可删除的属性:delete Object.prototype;
在严格模式下报错。
重复参数名:function(a, a) {}
在严格模式下报语法错误。
只读属性赋值:NaN = 1;
在严格模式下报错。
<script> function test1 (a, a) { delete Object.prototype; NaN = 1; } test1();</script><script>"use strict"; function test2 (a, a1) { // 报错 SyntaxError delete Object.prototype; // 报错 TypeError NaN = 1; // 报错 TypeError } test2();</script>
this 指向
非严格模式:全局函数中 this 指向全局对象(如 window)。
严格模式:全局函数中 this 为 undefined。
<script> function test1 () { console.log(this); // 浏览器中指向 Window 对象,nodejs 中指向 global 对象 } test1();</script><script>"use strict"; function test2 () { console.log(this); // undefined } test2();</script>
eval 和 arguments 限制
eval 变量泄漏:严格模式下 eval 中的变量不会污染外部作用域。
禁用 arguments.callee:防止递归调用导致性能问题。
<script> function test1 () { eval('var a = 10'); console.log(arguments.callee); // 指向函数本身 console.log(a); // 10 } test1();</script><script>"use strict"; function test2 () { eval('var a = 10'); console.log(arguments.callee); // 报错 TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them console.log(a); // ReferenceError: a is not defined } test2();</script>
其他限制
八进制表示:禁止 0123,需用 0o123。
with 语句:严格模式下禁用,避免作用域混乱。
保留字限制:如 interface、private 等不能作为变量名。
<script> function test1 () { console.log(0123); // 83 with (Math) { console.log(random()); // 输出随机数 } var interface = 'str'; console.log(interface); // str } test1();</script><script>"use strict"; function test2 () { console.log(0123); // SyntaxError: Octal literals are not allowed in strict mode. with (Math) { // SyntaxError: Strict mode code may not include a with statement console.log(random()); } var interface = 'str'; // SyntaxError: Unexpected strict mode reserved word console.log(interface); } test2();</script>
写在最后
建议始终启用严格模式,强制更安全的编码实践,避免隐式错误,提升代码质量。