家人们谁懂啊!刚学前端写 JavaScript 代码的时候,真的是状况百出。好几次代码运行结果和我想的完全不一样,找了好久才发现是因为 JavaScript 太 “惯着” 我了,有些明明写错的地方,它居然不报错!直到遇到严格模式,我才感觉自己的代码世界终于走上正轨了。
就拿变量声明来说,以前不声明变量直接用,JavaScript 就帮我 “擦屁股” 创建全局变量。像这样:
function test() {
message = "Hello, world!";
}
test();
console.log(message); // Hello, world!
但开了严格模式,在脚本或者函数开头加上'use strict';,再这么干就直接报错了。
'use strict';
function test() {
message = "Hello, world!";
}
test();
// 报错: Uncaught ReferenceError: message is not defined
这一下就治好了我不声明变量的臭毛病,也不用担心变量名冲突了。
对象属性这块也是,普通模式下随便加属性都没问题。
const person = { name: "Alice" };
person.age = 30;
console.log(person); // { name: "Alice", age: 30 }
但严格模式下,对象没这个属性还硬加,直接就报错,能帮我及时发现是不是属性名写错了。
'use strict';
const person = { name: "Alice" };
person.age = 30;
console.log(person)// 报错: Uncaught TypeError: Cannot create property 'age' on object
还有this指向的问题,我之前一直晕乎乎的。普通模式下,函数里的this在不同地方调用,指向都不一样,搞得我头大。严格模式就清爽多了,this不会默认指向全局对象(浏览器里是window),没绑定的话就是undefined,理解起来轻松多了。
function normalModeThis() {
console.log(this);
}
function strictModeThis() {
'use strict';
console.log(this);
}
normalModeThis(); // Window 对象
strictModeThis(); // undefined
上面就是严格模式的部分使用,它的作用可不是可以忽略的,它可以让代码更加规范。
下面让我将仔细说说严格模式的变化
1. 消除静默错误,让问题无所遁形
以前写代码最头疼的就是遇到那种不报错,但结果不对的情况。在非严格模式下,给未声明的变量赋值,JavaScript 会悄咪咪地创建一个全局变量,就像这样:
function test() {
message = "Hello, world!";
}
test();
console.log(message); // 输出: Hello, world!
当时我还纳闷为啥突然多出来个全局变量,找了半天才发现是变量声明写错了。但在严格模式下,这种操作直接就会抛出错误:
'use strict';
x = 10;
// ReferenceError: x is not defined
这样一来,代码里的小错误一下子就暴露出来,再也不用像个无头苍蝇一样到处找问题了。
2. 防止意外全局变量,规范变量声明
以前总偷懒,经常忘记用let、const或var声明变量,JavaScript 也不拦着我。但严格模式下,必须老老实实声明变量,不然就会报错。这虽然刚开始让我有点不适应,但慢慢养成习惯后,代码的作用域清晰多了,也很少出现变量命名冲突的问题。
3. 禁止删除不可删除的属性,避免 “手滑误操作”
有一回,我手贱想试试能不能删掉Object.prototype,在非严格模式下,虽然没成功但也没报错,给我一种 “好像能操作” 的错觉。但在严格模式下,直接给我报了个TypeError:
'use strict';
delete Object.prototype;
// TypeError
这就相当于给重要的属性上了把锁,再也不用担心不小心误删关键内容了。
4. 函数参数必须唯一,告别 “糊涂账”
写函数的时候,有时候脑子一抽,给函数定义了两个相同名字的参数,在非严格模式下,虽然能用但逻辑特别混乱。严格模式直接杜绝了这种情况,只要参数名重复,就会报SyntaxError:
'use strict';
function sum(a, a, c) {
// SyntaxError
return a + a + c;
}
这样函数的逻辑就清晰多了,再也不会自己把自己绕晕。
5. 禁止使用 with 语句,减少代码歧义
with语句我之前觉得挺方便的,但其实它特别容易让代码产生歧义,而且性能也不好。严格模式直接把它禁用了,一旦使用就会报SyntaxError:
'use strict';
with (obj) {}
// SyntaxError
虽然刚开始有点不习惯,但后来发现,不用with语句,代码反而更加简洁明了,可读性也提高了。
6. eval 行为变化,让作用域更可控
eval函数之前我用的时候总是小心翼翼,因为在非严格模式下,eval里声明的变量会泄漏到外部作用域,特别容易造成变量污染。但在严格模式下,eval中声明的变量只在eval内部有效,再也不用担心 “变量乱窜” 的问题了:
'use strict';
eval("var x = 10;");
console.log(x);
// ReferenceError
7. this 行为变化,理清作用域关系
this的指向问题,我之前简直被搞到怀疑人生,在不同场景下它的指向完全不一样。在非严格模式下,全局作用域中的this指向window,但在严格模式下,this的值变成了undefined,函数里的this也不会随便乱指了:
'use strict';
function test() {
console.log(this);
// undefined
}
test();
这样一来,我能更清楚地理解函数调用时this的作用域关系,写代码也更有底气了。
ES6 之后的async函数,在严格模式下this的处理也优化了。以前async函数的this指向很迷,现在终于稳定了,始终绑定在定义时的对象上。
'use strict';
const myObj = {
async asyncFunc() {
console.log(this);
}
};
myObj.asyncFunc(); // myObj 对象
8. 禁止八进制语法,统一代码规范
之前看到以0开头的数字,还以为是普通数字,后来才知道是八进制语法,而且不同环境下解析还可能有差异。严格模式直接禁止了这种写法,一旦出现就会报错:
'use strict';
var num = 010;
// SyntaxError
这样代码的规范就统一了,也避免了因为八进制语法带来的潜在问题。
9. 禁止对只读属性赋值,保护数据安全
有时候给对象设置了只读属性,结果不小心又去修改它的值,在非严格模式下不会报错,但其实数据已经被破坏了。严格模式下,对只读属性赋值会直接抛出TypeError:
'use strict';
var obj = {};
Object.defineProperty(obj, "x", { value: 42, writable: false });
obj.x = 9;
// TypeError
这就像是给数据加上了一层保护罩,保证数据的安全性和一致性。
刚开始用严格模式的时候,我老是被各种报错打击到,一度想放弃。但慢慢发现,这些报错其实是在帮我查漏补缺,逼着我养成好的编程习惯。