深度解析 JavaScript 严格模式:利弊长远的考量

news2024/10/3 8:31:35

前言

ECMAScript 5首次引入严格模式的概念。严格模式用于选择以更严格的条件检查JavaScript代码错误,可以应用到全局,也可以应用到函数内部。 严格模式的好处是可以提早发现错误,因此可以捕获某些 ECMAScript 问题导致的编程错误。

理解严格模式的规则非常重要,因为未来的 ECMAScript 会逐步强制全局使用严格模式。严格模式已得到所有主流浏览器支持。

1. 选择使用

要选择使用严格模式,需要使用严格模式编译指示 (pragma),即一个不赋值给任何变量的字符串:

"use strict" 

这样一个即使在 ECMAScript 3 中也有效的字符串,可以兼容不支持严格模式的 JavaScript 引擎。支持严格模式的引擎会启用严格模式,而不支持的引擎则会将这个编译指示当成一个未赋值的字符串字面量。

如果把这个编译指示应用到全局作用域,即函数外部,则整个脚本都会按照严格模式来解析。这意味着在最终会与其他脚本拼接为一个文件的脚本中添加了编译指示,会将该文件中的所有JavaScript置于严格模式之下。

也可以像下面这样只在一个函数内部开启严格模式:

function foo() {'use strict'console.log('CoderBin')// 其他代码
} 

如果你不能控制页面中的所有脚本,那么建议只在经过测试的特定函数中启用严格模式

2. 变量

严格模式下如何创建变量及何时会创建变量都会发生变化。第一个变化是不允许意外创建全局变量。在非严格模式下,以下代码可以创建全局变量:

// 变量未声明
// 非严格模式:创建全局变量
// 严格模式:抛出 ReferenceError
// 'use strict'
message = 'here is CoderBin' 

虽然这里的 message 没有前置 let 关键字,也没有明确定义为全局对象的属性,但仍然会自动创建为全局变量。在严格模式下,给未声明的变量赋值会在执行代码时抛出 ReferenceError

相关的另一个变化是无法在变量上调用delete 。在非严格模式下允许这样,但可能会静默失败(返回false )。在严格模式下,尝试删除变量会导致错误:

// 删除变量
// 非严格模式:静默失败
// 严格模式:抛出 ReferenceError
// 'use strict'
let color = 'red'
delete color 

严格模式也对变量名增加了限制。具体来说,不允许变量名为implements 、interface 、let 、package 、private 、protected 、public 、static 和yield 。这些是目前的保留字,可能在将来的ECMAScript版本中用到。如果在严格模式下使用这些名称作为变量名,则会导致语法错误。

3. 对象

在严格模式下操作对象比在非严格模式下更容易抛出错误。严格模式倾向于在非严格模式下会静默失败的情况下抛出错误,增加了开发中提前发现错误的可能性。

首先,以下几种情况下试图操纵对象属性会引发错误。

  • 给只读属性赋值会抛出 TypeError 。
  • 在不可配置属性上使用 delete 会抛出 TypeError 。
  • 给不存在的对象添加属性会抛出 TypeError 。

另外,与对象相关的限制也涉及通过对象字面量声明它们。在使用对象字面量时,属性名必须唯一。例如:

// 两个属性重名
// 非严格模式:没有错误,第二个属性生效
// 严格模式:抛出 SyntaxError
'use strict'
let person = {name: 'Coder',name: 'Bin'
} 

这里的对象字面量 person 有两个叫作 name 的属性。第二个属性在非严格模式下是最终的属性。但在严格模式下,这样写是语法错误。

注意:ECMAScript 6 删除了对重名属性的这个限制,即在严格模式下重复的对象字面量属性键不会抛出错误。

4. 函数

接下来让我们看看严格模式对函数有哪些限制。

4.1 命名参数

首先,严格模式要求命名函数参数必须唯一。看下面的例子:

// 命名参数重名
// 非严格模式:没有错误,只有第二个参数有效
// 严格模式:抛出SyntaxError
function sum(num, num) {// 'use strict'// 函数代码
} 

在非严格模式下,这个函数声明不会抛出错误。这样可以通过名称访问第二个 num ,但只能通过 arguments 访问第一个参数。

4.2 arguments 对象

arguments 对象在严格模式下也有一些变化。在非严格模式下,修改命名参数也会修改 arguments 对象中的值。而在严格模式下,命名参数和 arguments 是相互独立的。例如:

// 修改命名参数的值
// 非严格模式:arguments 会反映变化
// 严格模式:arguments 不会反映变化
function showValue(value) {// 'use strict'value = 'Foo'console.log(value)// "Foo"console.log(arguments[0])// 非严格模式:"Foo"// 严格模式:"Hi"
}
showValue('Hi') 

在这个例子中,函数 showValue() 有一个命名参数 value 。调用这个函数时给它传入参数 “Hi” ,该值会赋给 value 。在函数内部,value 被修改为"Foo" 。在非严格模式下,这样也会修改 arguments[0] 的值, 但在严格模式下则不会。

4.3 arguments 对象属性

另一个变化是去掉了 arguments.calleearguments.caller。在非严格模式下,它们分别引用函数本身和调用函数。在严格模式下,访问这两个属性中的任何一个都会抛出 TypeError 。例如:

// 访问arguments.callee
// 非严格模式:没问题
// 严格模式:抛出TypeError
function factorial(num) {// 'use strict'if (num <= 1) {return 1} else {return num * arguments.callee(num - 1)}
}
let result = factorial(5)
console.log(result) 

类似地,读或写函数的 caller 或 callee 属性也会抛出 TypeError。 因此对这个例子而言,访问 factorial.callerfactorial.callee 也会抛出错误。

另外,与变量一样,严格模式也限制了函数的命名,不允许函数名为 implements 、interface 、let 、package 、private 、 protected 、public 、static 和 yield 。

4.4 函数声明

关于函数的最后一个变化是不允许函数声明,除非它们位于脚本或函数的顶级。这意味着在 if 语句中声明的函数现在是个语法错误:

// 在if语句中声明函数
// 非严格模式:函数提升至if语句外部
// 严格模式:抛出 ReferenceError
'use strict'
if (true) {function foo() {console.log('CoderBin')}
}
foo() 

所有浏览器在非严格模式下都支持这个语法,但在严格模式下则会抛出语法错误。

4.5 函数参数

ES6 增加了剩余操作符、解构操作符和默认参数,为函数组织、结构和定义参数提供了强大的支持。ECMAScript 7 增加了一条限制,要求使用任何上述先进参数特性的函数内部都不能使用严格模式,否则会抛出错误。不过,全局严格模式还是允许的。

// 可以
function foo(a, b, c) {'use strict'
}
// 不可以
function bar(a, b, c = 'd') {'use strict'
}
// 不可以
function baz({ a, b, c }) {'use strict'
}
// 不可以
function qux(a, b, ...c) {'use strict'
} 

ES6增加的这些新特性期待参数与函数体在相同模式下进行解析。如果允许编译指示 “use strict” 出现在函数体内,JavaScrip t解析器就需要在解析函数参数之前先检查函数体内是否存在这个编译指示,而这会带来很多问题。为此,ES7规范增加了这个约定,目的是让解析器在解析函数之前就确切知道该使用什么模式。

5. eval() 函数

eval() 函数在严格模式下也有变化。最大的变化是 eval() 不会再在包含上下文中创建变量或函数。例如:

// 使用eval()创建变量
// 非严格模式:输出10
// 严格模式:调用 console.log(x)时抛出 ReferenceError
function foo() {eval('let x = 10')console.log(x)
}
foo() 

以上代码在非严格模式下运行时,会在 foo() 函数内部创建局部变量 x ,然后 console.log() 会输出这个变量的值。在严格模式下,调用 eval() 不会在 foo() 中创建变量 x ,由于 x 没有声明, console.log() 会抛出 ReferenceError 。

变量和函数可以在 eval() 中声明,但它们会位于代码执行期间的一个特殊的作用域里,代码执行完毕就会销毁。因此,以下代码就不会出错:

'use strict'
let result = eval('let x = 10, y = 11; x + y')
console.log(result) // 21 

这里在 eval() 中声明了变量 x 和 y ,将它们相加后返回得到的结果。变量 result 会包含x 和y 相加的结果 21,虽然 x 和 y 在调用 console.log() 时已经不存在了,但不影响结果的显示。

6. eval() 和 arguments

严格模式明确不允许使用 eval 和 arguments 作为标识符和操作它们的值。例如:

// 将 eval和 arguments 重新定义为变量
// 非严格模式:可以,没有错误
// 严格模式:抛出SyntaxError
// 'use strict'
let eval = 10
let arguments = 'Hello CoderBin!' 

在非严格模式下,可以重写 eval 和 arguments 。在严格模式下,这样会导致语法错误。不能用它们作为标识符,这意味着下面这些情况都会抛出语法错误:

  • 使用let 声明;
  • 赋予其他值;
  • 修改其包含的值,如使用++ ;
  • 用作函数名;
  • 用作函数参数名;
  • 在try /catch 语句中用作异常名称。

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/347702.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端vue实现系统拦截跳转外链并进入跳转询问界面

跳转询问界面如下图所示&#xff1a; 给自己挖坑的实现方式&#xff0c;最终解决方案请看最底下 思路&#xff1a;正常情况下我们有2种方式跳转外链 第一种非a标签&#xff0c;我们手动添加事件进行跳转 <div class"dingdan public-padding p-item" click&quo…

Python 条件语句是什么?

Python条件语句是通过一条或多条语句的执行结果&#xff08;True或者False&#xff09;来决定执行的代码块。 可以通过下图来简单了解条件语句的执行过程: Python程序语言指定任何非0和非空&#xff08;null&#xff09;值为true&#xff0c;0 或者 null为false。 Python 编程…

家政服务小程序实战教程12-详情页

我们的家政服务小程序已经完成了首页和分类展示页面的开发&#xff0c;接下来就需要开发详情页了。在详情页里我们展示我们的各项服务内容&#xff0c;让用户可以了解每项家政服务可以提供的内容。 低码开发不像传统开发&#xff0c;如果开发详情页需要考虑每个字段的类型&…

【TPC证书报错--箱码校验失败】

证书管理—>交易证书管理—>编辑&#xff0c;然后就报错了。 1.这个报错&#xff0c;一般是指一个箱码&#xff0c;【产出/报工】接口失败了&#xff0c;但是【成品入库】和【成品出口】成功了。 2.大概就是【成品出库】接口&#xff0c;会传【销售单号】和【箱码】2个…

ArcGIS与地理加权回归【三】

开 工 大 急 原址链接&#xff1a; ArcGIS与地理加权回归【三】https://mp.weixin.qq.com/s/x85EXKImSHio1IZovW9qdA 接着5个月之前.......ArcGIS与地理加权回归GWR【二】以及MGWR软件下载 在ASU下载了样例“关于影响佐治亚州受教育水平”的数据。在上一篇已简单介绍…

类和对象(下)(一)

类和对象&#xff08;下&#xff09;&#xff08;一&#xff09;1.再谈构造函数1.1构造函数体赋值1.2初始化列表1.3explicit关键字2.static成员2.1概念2.2特性3.匿名对象&#x1f31f;&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f;&#x1f31f; &#x…

Spring框架源码(五) @configuration源码深度解析

Configuration 注解是spring-context模块提供的一个给开发者使用的配置类注解&#xff0c;开发者可以通过Configuration注解来定义配置类&#xff0c;也可以使用xml形式注入。 例如配置数据库配置&#xff0c;定义一个配置类&#xff0c;注入数据源DataSource, 事务管理器Trans…

类和对象(下)(二)

类和对象&#xff08;下&#xff09;&#xff08;二&#xff09;1.友元1.1友元函数1.2友元类2.内部类3.拷贝对象时的一些编译器优化&#xff08;vs2022&#xff09;&#x1f31f;&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f;&#x1f31f; &#x1f680…

【c#】反射学习笔记01

c#反射学习01反射学习一、反射原理二、那么我们是如何通过metadata来实现反射呢&#xff1f;三、反射的好处四、反射创建对象&#xff08;利用配置文件简单工厂反射&#xff09;五、反射的黑科技&#xff08;多构造函数调用、破坏单例、创建泛型&#xff09;六、反射调用实例方…

环境配置完整指导——Installing C++ Distributions of PyTorch

目录一、前言二、动手开始做1. 安装cuda 11.42. 安装visual studio 2019 community3. 安装libtorch4. 安装mingw-w645. 配置环境变量6. 打开vscode开始写程序7. 运行程序8. 其他报错信息文章简介&#xff1a;这篇文章用于介绍在windows10 vscode中&#xff0c;跑通如下代码的全…

JavaScript 教程导读

JavaScript 是 Web 的编程语言。所有现代的 HTML 页面都使用 JavaScript&#xff0c;可以用于改进设计、验证表单、检测浏览器、创建cookies等。JavaScript 非常容易学。本教程将教你学习从初级到高级JavaScript知识。JavaScript 在线实例本教程包含了大量的 JavaScript 实例&a…

使用 ONLYOFFICE 转换 API 构建在线文档转换器

文档转换是非常常用、非常有价值的功能&#xff0c;可以帮助我们处理多种文档类型。ONLYOFFICE 编辑器可以轻松地将文档转换为多种格式。在这篇博文中&#xff0c;我们会向您展示&#xff0c;如何构建在 ONLYOFFICE 转换 API 上运行的在线转换器。 关于 ONLYOFFICE 转换 API 使…

傻白探索Chiplet,Design Space Exploration for Chiplet-Assembly-Based Processors(十三)

阅读了Design Space Exploration for Chiplet-Assembly-Based Processors这篇论文&#xff0c;是关于chiplet设计空间探索的&#xff0c;个人感觉核心贡献有两个&#xff1a;1.提出使用整数线性规划算法进行Chiplet的选择&#xff1b;2.基于RE和NRE提出了一个cost模型&#xff…

Map和Set(Java详解)

在开始详解之前&#xff0c;先来看看集合的框架&#xff1a; 可以看到Set实现了Collection接口&#xff0c;而Map又是一个单独存在的接口。 而最下面又分别各有两个类&#xff0c;分别是TreeSet&#xff08;Map&#xff09;和 HashSet&#xff08;Map&#xff09;。 TreeSet&…

CSS---动态向下的循环箭头动画效果

介绍 在移动端的页面中&#xff0c;经常有翻页的提示效果&#xff0c;经常使用向下的箭头动画来提示&#xff1b;一般效果如下所示&#xff1a; 使用到的图片 使用到的图片&#xff0c;就是一个向下的箭头&#xff1b;这里可以下载我的图片使用&#xff1b; 或者也可以使用…

92.【SpringCloud NetFilx】

SpringCloud(一)、这个阶段该如何学习?1.微服务介绍2.面试常见问题(二)、微服务概述1.什么是微服务?2. 微服务与微服务架构(1).微服务(2).微服务架构⭐(3). 微服务优缺点(4). 微服务技术栈有那些&#xff1f;(5). 为什么选择SpringCloud作为微服务架构(三)、SpringCloud入门概…

Python 之 Matplotlib 第一个绘图程序和基本方法

文章目录一、第一个 Matplotlib 绘图程序1. Matplotlib 绘图的基本步骤二、Matplotlib 的基本方法1. 图表名称 plt.title()2. x 轴和 y 轴名称3. 设置 x 轴和 y 轴的刻度4. 显示图表 show()5. 图例 legend()6. 图例的图例位置设置7. 显示每条数据的值 x,y 值的位置一、第一个 M…

LeetCode 61. 旋转链表

原题链接 难度&#xff1a;middle\color{orange}{middle}middle 题目描述 给你一个链表的头节点 headheadhead &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 kkk 个位置。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], k 2 输出&#xff1a;[4,5,1…

wafw00f源码及流量特征分析

wafw00f介绍 这不是本次的重点&#xff0c;相关介绍及使用方法相信大家已经了解&#xff0c;所以此处就直接引用其开发者对该工具的介绍。 To do its magic, WAFW00F does the following: Sends a normal HTTP request and analyses the response; this identifies a number o…

(考研湖科大教书匠计算机网络)第四章网络层-第三节3、4:划分子网的IPv4地址和无分类IP地址

获取pdf&#xff1a;密码7281专栏目录首页&#xff1a;【专栏必读】考研湖科大教书匠计算机网络笔记导航 文章目录一&#xff1a;划分子网的IPv4地址&#xff08;1&#xff09;划分子网思想&#xff08;2&#xff09;子网掩码A&#xff1a;概述B&#xff1a;例子C&#xff1a;默…