持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情
JS严格模式有什么特点?【1】
严格模式的特点有很多,本章就介绍主要的一部分,主要是太多了,太细节了,我们先掌握主要的就好了!
背景介绍
网景公司要求给浏览器添加一个脚本功能 公司要求这个脚本必须蹭Java的流量 Brendan Eich花十天设计了JS的最初版本(不是实现) 总的来说,他的设计思路是这样的:
- 借鉴C语言的基本语法;
- 借鉴Java语言的数据类型和内存管理;
- 借鉴Scheme语言,将函数提升到"第一等公民"(first class)的地位;
- 借鉴Self语言,使用基于原型(prototype)的继承机制。
Javascript语言实际上是两种语言风格的混合产物----(简化的)函数式编程+(简化的)面向对象编程。
因为种种原因,导致 JS 有很多缺陷。随着这些年的发展,现在各种工具和新标准也慢慢的弥补上了一些问题。但是有些问题还是存在的。特别是在生产环境下,我们打包出来的代码还是需要满足 ES5的标准,所以说我们一般在生产环境下就会用严格模式。所以严格模式下的有些问题我们需要去规避。那么?如果在非严格模式下规避这些问题?
开启严格模式
全局作用域下的严格模式
想要在全局作用域下启用严格模式,只需要在任意其他代码之前写上"use strict";
(或者'use strict';
)。
// 全局作用域下的严格模式语法
'use strict';
var v = "Hi! I'm a strict mode script!";
为函数开启严格模式
同样的,要给某个函数开启严格模式,得把 "use strict";
(或 'use strict';
) 声明一字不漏地放在函数体所有语句之前。
function strict() {
// 函数级别严格模式语法
'use strict';
...
}
严格模式的特点
- 全局变量必须先声明
- 禁止使用 with
- 创建 eval 作用域
- 禁止 this 指向 window
- 函数参数不能重名
全局变量必须先声明
<!DOCTYPE html>
<html>
<body>
<h1>全局变量必须先声明</h1>
<script>
"use strict";
x = 3.14; // 会引发错误(x 未定义)
</script>
</body>
</html>
这样在浏览器的控制台中是会出现报错的,为什么呢?
在普通的 JavaScript 里面给一个错误命名的变量名赋值会使全局对象新增一个属性并继续“工作”(尽管将来可能会失败:在现代的 JavaScript 中有可能)。严格模式中意外创建全局变量被抛出错误替代
为什么禁止使用 with ?
const obj = { x: 100, y:200}
with(obj) {
console.log(x,y) // 这里的输出是 100, 200
}
也就是我们使用 with 的时候,我们可以去改变内部取值的主题。就如上面的例子中console.log(x,y)
取值的对象是obj
,这样就给我们带来了很大的割裂感
引用官方文档上的话:
JavaScript 查找某个未使用命名空间的变量时,会通过作用域链来查找,作用域链是跟执行代码的 context 或者包含这个变量的函数有关。'with'语句将某个对象添加到作用域链的顶部,如果在 statement 中有某个未使用命名空间的变量,跟作用域链中的某个属性同名,则这个变量将指向这个属性值。如果沒有同名的属性,则将拋出
ReferenceError
异常。备注: 不推荐使用
with
,在 ECMAScript 5 严格模式中该标签已被禁止。推荐的替代方案是声明一个临时变量来承载你所需要的属性。
创建 eval 作用域
不使用严格模式先来一个例子:
var x = 20
console.log('第一次输出', x)
eval(`var x = 30; console.log('eval中输出',x)`)
console.log('第三次输出',x)
输出:
这出乎意料的输出。。eval的作用域居然还是自己的一套,甚至影响了我们的
x
这个全局变量。。。
使用严格模式:
"use strict";
var x = 20
console.log('第一次输出', x)
eval(`var x = 30; console.log('eval中输出',x)`)
console.log('第三次输出',x)
输出:
虽然 eval 的作用域还是自己的一套,但是没有影响我们的 x 全局变量了
ps:一般也不推荐使用 eval,他的性能也是差的离谱。。。感兴趣的同学可以去看看拓展链接【2】的文章
禁止 this 指向 window
由于非严格模式下有些写法其实是不大符合逻辑的,比如在顶级作用域中使用var声明的变量会自动成为全局变量,还有调用普通方法时会自动将方法绑定到window对象中。
严格模式中顶级作用域下调用普通函数的时候,不会自动将函数绑定到window对象,导致函数的调用者丢失,此时函数内的this相当于未初始化的普通变量,为undefined。
函数参数不能重名
这没啥好解释为啥得了吧?
总结一下
根据二八原则我们需要记住的
- 全局变量必须先声明
- 禁止使用 with
- 创建 eval 作用域
- 禁止 this 指向 window
- 函数参数不能重名