当前位置: 首页 > news >正文

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

前言

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的提问。



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

相关文章:

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

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

Vue.js 循环语句

Vue.js 循环语句 在Vue开发中&#xff0c;for循环是我们最常遇见的场景之一&#xff0c;我们知道常见的遍历方式有for循环&#xff0c;for of、forEach、for in.虽然在开发过程中&#xff0c;这几种方式基本上可以满足我们大多数的场景&#xff0c;但是你真的知道他们之间的区…...

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

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

十四、平衡二叉树

1、看一个案例&#xff08;说明二叉排序树可能的问题&#xff09; 给你一个数列{1,2,3,4,5,6}&#xff0c;要求创建一棵二叉排序树&#xff08;BST&#xff09;&#xff0c;并分析问题所在。 上面二叉排序树存在问题分析&#xff1a; 左子树全部为空&#xff0c;从形式上看&…...

AC/DC 基础

一、概念&#xff1a; AC转换成DC的基本方法有变压器方式和开关方式&#xff0c;如下图1、2所示&#xff1b;整流的基本方法有全波整流和半波整流&#xff0c;如下图3所示。 图1 变压器方式 图2 开关方式 图3 整流方式 二、转换方式 1、变压器方式 变压器方式首先需要通过变压…...

集成电路相关书籍

注&#xff1a;从此开始&#xff0c;文中提到的书籍都会在公众号对应文章末尾给出链接&#xff0c;不需要在微信后台获取&#xff0c;当然还是可以通过在微信后台回复相关书名获取对应的电子书。 在后台看到很多人回复集成电路相关的一些书籍&#xff0c;所以本文就提供一些书籍…...

前端开发之防抖与节流

前端开发中我们经常会通过监听某些事件来完成项目需求 1.通过监听 scroll 事件&#xff0c;检测滚动位置&#xff0c;根据滚动位置显示返回顶部按钮 2.通过监听 resize 事件&#xff0c;对某些自适应页面调整DOM的渲染&#xff08;通过CSS实现的自适应不再此范围内&#xff09;…...

大公司如何用A/B测试解决增长问题?

摘要&#xff1a;上线六年&#xff0c;字节跳动的短视频产品——抖音已成为许多人记录美好生活的平台。除了抖音&#xff0c;字节跳动旗下还同时运营着数十款产品&#xff0c;从资讯、游戏&#xff0c;到房产、教育等横跨多个领域。在产品迭代速度和创新能力的快速发展下&#…...

【Airplay_BCT】Bonjour API架构

Bonjour API 架构 OS X 和 iOS 为 Bonjour 服务应用程序提供了多层应用程序编程接口 (API)&#xff1a; Foundation 框架中的 NSNetService 和 NSNetServiceBrowser 类&#xff1b; CFNetServices&#xff0c;Core Services 中 CFNetwork 框架的一部分&#xff1b; Java 的 DN…...

为什么sleeping的会话会造成阻塞(2)

背景客户反馈系统突然从11:10开始运行非常缓慢&#xff0c;在SQL专家云中看到大量的产生阻塞的活动会话&#xff0c;KILL掉阻塞的源头马上又出现新的源头&#xff0c;实在没有办法只能重启应用程序断开所有数据库连接才解决&#xff0c;请我们协助分析根本的原因。现象登录SQL专…...

从矩阵中提取对角线元素;将一维数组转换为对角线矩阵:np.diag()函数

【小白从小学Python、C、Java】【计算机等级考试500强双证书】【Python-数据分析】从矩阵中提取对角线元素将一维数组转换为对角线矩阵np.diag()函数选择题下列说法错误的是?import numpy as npmyarray1 np.array([1,2,3])print("【显示】myarray1")print(myarray1…...

JavaSE学习day7_02 封装和构造方法

4. 封装 面向对象的三大特征&#xff1a; 封装、继承、多态 封装&#xff1a;对象代表什么&#xff0c;就得封装对应的数据&#xff0c;并提供数据对应的行为。 比如人画圆&#xff1a;”画“这个行为应该封装在圆这个类&#xff0c;为什么&#xff1f;因为”画“圆要知道圆…...

2022年FIT2CLOUD飞致云开源成绩单

2023年2月15日&#xff0c;中国领先的开源软件公司FIT2CLOUD飞致云发布《2022年开源成绩单》&#xff0c;盘点公司2022年全年在开源软件产品与社区运营方面的表现。目前&#xff0c;飞致云旗下的核心开源软件组合包括JumpServer开源堡垒机、DataEase开源数据可视化分析平台、Me…...

【Python】asyncio使用注意事项

目录协程的定义协程的运行多个协程运行关于loop.close()回调事件循环协程的定义 需要使用 async def 语句 协程可以做哪些事: 1、等待一个future结果 2、等待另一个协程(产生一个结果或引发一个异常) 3、产生一个结果给正在等它的协程 4、引发一个异常给正在等它的协程 …...

成都链安受邀参加第五届CCF中国区块链技术大会

2月10-12日&#xff0c;由中国计算机学会主办的&#xff0c;2023年国内首场大型区块链学术会议—第五届CCF中国区块链技术大会在无锡市成功举办&#xff0c;成都链安作为区块链安全头部企业受邀参加此次大会。大会上&#xff0c;成都链安创始人&CTO郭文生教授与锡东新城商务…...

验证码识别--封装版

前面我们说过了数字英文的验证码识别操作&#xff0c;本章我们对其进行完善一下&#xff0c;结合selenium来实际操作操作。import osimport timedef coding_path(path):Base_Path os.path.abspath(os.path.dirname(os.path.abspath(__file__)) /..)Base_image os.path.join(…...

创建Wails项目

项目生成​ 现在 CLI 已安装&#xff0c;您可以使用 wails init 命令生成一个新项目。 选择您最喜欢的框架&#xff1a; SvelteReactVuePreactLitVanilla 使用 JavaScript 生成一个 Vue 项目: wails init -n myproject -t vue如果您更愿意使用 TypeScript: wails init -…...

深度解析UG二次开发装配的部件事件、部件原型和部件实例

做UG二次开发快一年了&#xff0c;每次遇到装配的问题涉及到部件事件、部件原型和部件实例还是一头雾水&#xff0c;什么是实例&#xff0c;什么是原型这些专业术语等等。 针对这个问题&#xff0c;今天专门写了一篇特辑&#xff0c;结合装配实例深度剖析装配过程中的的所有参数…...

Linux安装elasticsearch-head

elasticsearch-head 是一款专门针对于 elasticsearch 的客户端工具&#xff0c;用来展示数据。 elasticsearch-head 是基于 JavaScript 语言编写的&#xff0c;可以使用 Nodejs 下的包管理器 npm 部署。 1 安装Nodejs nodejs下载地址&#xff1a; https://nodejs.org/en/dow…...

MySQL InnoDB表的碎片量化和整理(data free能否用来衡量碎片?)

网络上有很多MySQL表碎片整理的问题&#xff0c;大多数是通过demo一个表然后参考data free来进行碎片整理&#xff0c;这种方式对myisam引擎或者其他引擎可能有效&#xff08;本人没有做详细的测试&#xff09;.对Innodb引擎是不是准确的&#xff0c;或者data free是不是可以参…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...