什么是JavaScript中的"use strict",为什么它备受争议?
\n\n你是否曾经写过运行起来“有点奇怪”的JavaScript代码?变量自己就声明了,this指向了全局对象而不是你期望的对象,错误被默默地吞掉了?欢迎来到“脏”JS的世界。
"use strict"指令既不是函数也不是运算符。它实际上是你脚本或函数的模式切换开关。当你在文件或函数的开头写上"use strict"时,你就是在告诉JavaScript引擎:“嘿,不要原谅我的错误。要更严格,但也要更诚实。”
这个话题是Stack Overflow上最热门的问题之一(有数千次浏览)。让我们来弄清楚严格模式到底做了什么,为什么它被发明出来,以及如何用它来避免搬起石头砸自己的脚。
\n\n如何启用严格模式?
\n\n只有两种方法:
\n\n- \n
- 全局(针对整个脚本): 在文件的第一行写上
"use strict";。 \n - 局部(针对函数): 在函数体的第一行写上
"use strict";。 \n
// 全局严格模式\n"use strict";\nlet x = 10;\n\n// 局部严格模式\nfunction myFunc() {\n "use strict";\n let y = 20;\n}\n\n重要提示: 如果你在同一个文件中混合使用严格和非严格代码(例如,拼接脚本),可能会出现问题。最好对单个函数或模块使用严格模式(ES6模块自动处于严格模式)。
\n\n"use strict"防止的5大错误
\n\n"use strict"的主要目标是将JavaScript的“静默”错误转化为显式异常(可以被捕获并抛出的错误)。以下是5个最常见的场景。
1. 禁止隐式创建全局变量
\n\n这是经典案例。在普通模式下,如果你忘记写var、let或const,变量会自动变成全局变量。这可能导致难以发现的bug。
// 没有"use strict"\nfunction sum(a, b) {\n total = a + b; // 错误?不。total变成了全局变量!\n}\nsum(2, 3);\nconsole.log(total); // 5 — 可以运行,但这很糟糕。\n\n// 使用"use strict"\n"use strict";\nfunction sumStrict(a, b) {\n total = a + b; // ReferenceError: total is not defined\n}\nsumStrict(2, 3); // 错误!代码会立即崩溃。\n\n如何避免? 始终声明变量。使用let和const代替var,以避免变量提升和意外的全局变量。
2. 给不可写的属性赋值
\n\n在普通模式下,JavaScript会默默地忽略修改NaN、undefined或冻结对象的尝试。在严格模式下,会抛出错误。
"use strict";\n\n// 尝试重写NaN\nNaN = 123; // TypeError: Cannot assign to read only property 'NaN'\n\n// 尝试修改冻结对象\nconst obj = Object.freeze({name: "Alice"});\nobj.name = "Bob"; // TypeError: Cannot assign to read only property 'name'\n\n如何避免? 不要尝试重写内置常量。有意识地使用Object.freeze()。
3. 删除变量、函数和参数
\n\n你不能删除通过var或let声明的变量,也不能删除函数。在普通模式下,这会被忽略。
"use strict";\n\nvar x = 10;\ndelete x; // SyntaxError: Delete of an unqualified identifier in strict mode.\n\nfunction foo() {}\ndelete foo; // SyntaxError\n\n如何避免? 不要对变量使用delete。它只用于删除对象的属性:delete obj.prop。