先记住这个答案
非严格模式下有些操作「静默失败」——执行了但不报错也不生效。比如给 Object.freeze 冻结的对象加属性,赋值语句正常走完,但属性根本没加上。严格模式把这类静默失败升级为抛异常,让错误第一时间暴露出来,而不是藏在运行结果里等你慢慢排查。
- 给只读属性赋值会抛
TypeError delete不可配置属性同理,严格模式报错- 函数参数重名在严格模式下是语法错误
- 未声明变量赋值在严格模式抛
ReferenceError
最典型的场景:给只读属性赋值
只读属性赋值是面试里问得最多的例子。Object.defineProperty 设了 writable: false、Object.freeze 冻结的对象、只有 getter 没有 setter 的访问器属性,赋值时都会触发这个区别。
'use strict'
var obj = {}
Object.defineProperty(obj, 'x', { value: 1, writable: false })
try {
obj.x = 2 // 严格模式下抛 TypeError
} catch (e) {
console.log(e.constructor.name)
console.log(obj.x) // 赋值没生效,还是 1
}查看输出与解释
TypeError
1非严格模式下同样的 obj.x = 2 不会报错,但 obj.x 还是 1。这种「不报错也不生效」是最容易埋坑的情况——你以为改了,其实没改,直到上线才发现数据不对。
删除不可配置属性和未声明变量
delete 一个 configurable: false 的属性,非严格模式下返回 false 就完了,严格模式直接抛 TypeError。比如 delete Object.prototype 就会触发这个错误,因为内置对象的属性大多是不可配置的。
另一个高频场景是给未声明的变量赋值。非严格模式下写 x = 1,如果没有用 var、let 或 const 声明,会在全局对象上偷偷创建一个属性。严格模式下这行直接抛 ReferenceError,逼你把声明补上。
'use strict'
try {
undeclaredVar = 42 // 严格模式下抛 ReferenceError
} catch (e) {
console.log(e.constructor.name)
}查看输出与解释
ReferenceError这条规则最大的好处是帮你发现拼错变量名的 bug。非严格模式下 nubmer = 1(拼错了 number)不会报错,会偷偷创建一个全局变量 nubmer,排查起来很痛苦。
语法层面的限制
还有几条规则在语法分析阶段就报错,代码根本执行不到。
函数参数重名在非严格模式下合法,后面的会覆盖前面的。比如 function f(a, a) {} 在非严格模式是允许的,严格模式下直接 SyntaxError。
八进制字面量 0123 在非严格模式下等于 83(八进制的 123),严格模式下也报 SyntaxError,要写八进制得用 0o123。with 语句在严格模式下同样被禁止,因为它让作用域变得不可预测,引擎没法做优化。
这些语法限制的目的都一样:消除含糊的写法,让引擎能做更好的优化,也让代码的行为更可预测。
容易答错的地方
- 把所有严格模式变化都说成「静默变报错」
- 严格模式的改变不只是把静默错误变成异常。
this在普通函数调用时变成undefined、arguments和形参不再同步、禁止with语句,这些是语义层面的变化,不属于「静默错误转异常」。面试时把这两类分开说,条理更清楚。 - 以为严格模式需要手动开启
- ES 模块和
class内部默认就是严格模式。现在的项目基本都用打包工具把文件编译成模块,所以严格模式是默认行为。只有在老项目的普通<script>标签里才需要手动加"use strict"。
面试官还会怎么问?
Object.freeze 和 Object.seal 在严格模式下有什么区别?
Object.freeze 冻结后不能增、删、改任何属性;Object.seal 密封后不能增、删属性,但已有的可写属性仍然可以改值。严格模式下违反这些约束都会抛 TypeError,区别在于约束范围不同。
严格模式下 arguments 和参数还是同步的吗?
不是。非严格模式下修改 arguments[0] 会同步改变对应的形参,严格模式下两者各自独立。这也是消除意外行为的设计,让函数参数的值更可预测。
在非严格函数里调用严格函数,会怎样?
严格模式按函数为单位生效。外层非严格的函数里调用一个 "use strict" 函数,或者调用 class 方法、ES 模块里的函数,被调用的函数内部按严格模式执行,外层不受影响。两种模式可以在同一个程序里共存。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。