当前位置: 首页 > 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是不是可以参…...

Leetcode-每日一题1250. 检查「好数组」(裴蜀定理)

题目链接&#xff1a;https://leetcode.cn/problems/check-if-it-is-a-good-array/description/ 思路 方法&#xff1a;数论 题目意思很简单&#xff0c;让你在数组 nums中选取一些子集&#xff0c;可以不连续&#xff0c;子集中的每个数再乘以任意的数的和是否为1&#xff…...

OpenStack手动分布式部署环境准备【Queens版】

目录 1.基础环境准备&#xff08;两个节点都需要部署&#xff09; 1.1关闭防火墙 1.2关闭selinux 1.3修改主机名 1.4安装ntp时间服务器 1.5修改域名解析 1.6添加yum源 2.数据库安装配置 2.1安装数据库 2.2修改数据库 2.3重启数据库 2.4初始化数据库 3.安装RabbitMq…...

Web自动化测试——selenium的使用

⭐️前言⭐️ 本篇文章就进入了自动化测试的章节了&#xff0c;如果作为一名测试开发人员&#xff0c;非常需要掌握自动化测试的能力&#xff0c;因为它不仅能减少人力的消耗&#xff0c;还能提升测试的效率。 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f…...

虚拟交换单元技术

支持VSU&#xff08;Virtual Switch Unit&#xff09;即虚拟交换单元技术。通过聚合链路连接&#xff0c;将多台物理设备虚拟为一台逻辑上统一的设备&#xff0c;使其能够实现统一的运行&#xff0c;利用单一IP 地址、单一Telnet 进程、单一命令行接口(CLI)、自动版本检查、自动…...

【STM32笔记】HAL库外部定时器、系统定时器阻塞、非阻塞延时

【STM32笔记】HAL库外部定时器、系统定时器阻塞、非阻塞延时 外部定时器 采用定时器做延时使用时 需要计算好分频和计数 另外还要配置为不进行自动重载 对于50MHz的工作频率 分频为50-1也就是50M/501M 一次计数为1us 分频为50000-1也就是1k 一次计数为1ms 我配置的是TIM6 只…...

[Springboot 单元测试笔记] - Mock 和 spy的使用

Springboot单元测试 - 依赖类mock测试 通常单元测试中&#xff0c;我们会隔离依赖对于测试类的影响&#xff0c;也就是假设所有依赖的一定会输出理想结果&#xff0c;在测试中可以通过Mock方法来确保输出结果&#xff0c;这也就引入另一个测试框架Mockito。 Mockito框架的作用…...

互联网新时代要来了(二)什么是AIGC?

什么是AIGC&#xff1f; 最近&#xff0c;又火了一个词“**AIGC”**2022年被称为是AIGC元年。那么我们敬请期待&#xff0c;AIGC为我们迎接人工智能的下一个时代。 TIPS:内容来自百度百科、知乎、腾讯、《AIGC白皮书》等网页 什么是AIGC&#xff1f;1.什么是AIGC&#xff1f;…...

75V的TVS二极管有哪些型号?常用的

瞬态抑制TVS二极管工作峰值反向电压最低3.3V&#xff0c;最高可达513V&#xff0c;甚至更高。很多电子工程师都知道&#xff0c;TVS二极管在实际应用选型过程中&#xff0c;第一步要确认的就是其工作峰值反向电压。2023年春节已过&#xff0c;东沃电子正月初八就开工了&#xf…...

测试开发之Django实战示例 第十章 创建在线教育平台

第十章 创建在线教育平台在上一章&#xff0c;我们为电商网站项目添加了国际化功能&#xff0c;还创建了优惠码和商品推荐系统。在本章&#xff0c;会建立一个新的项目&#xff1a;一个在线教育平台&#xff0c;并创内容管理系统CMS&#xff08;Content Management System&…...

Hadoop高可用搭建(二)

目录 解压Hadoop 改名 更改配置文件 workers hdfs-site.xml core-site.xml hadoop-env.sh mapred-site.xml yarn-site.xml 设置环境变量 启动集群 启动zk集群 启动journalnode服务 格式化hfds namenode 启动namenode 同步namenode信息 查看namenode节点状态 …...

徐州沛县网站建设/站长工具查询网站

IOS App 技术支持网址 有问题的可以留言 邮箱地址&#xff1a;lqy1024foxmail.com 谢谢&#xff01; IOS app Technical Support Website You can leave a message if you have any questions Email address: lqy1024foxmail.com Thank you&#xff01;...

谷歌seo和sem/温州网站优化推广方案

C#基础知识梳理系列索引 摘 要这个系列&#xff0c;将从山脚写到山腰。由于鄙人知识匮乏&#xff0c;不敢奢望攀登山顶。 C# Target Runtime: v4.0.30319 系列索引C#基础知识梳理系列一&#xff1a;CLR及程序集部署 C#基础知识梳理系列二&#xff1a;C#的演绎大师&#xff1a;类…...

购物网站开发/用模板快速建站

(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/73477461冷血之心的博客)...

中国建设银行官网站e路护航/谷歌搜索引擎大全

试了下, redis之del命令不支持按模式删除key, 如 del user:*这种行不通. 但是可以这样(先redis-cli连上redis-server): EVAL "return redis.call(del, unpack(redis.call(keys, ARGV[1])))" 0 user:*原因是: del命令支持不定参数, 而上面的unpack函数就可以将数组转…...

无锡专业做网站/今天的新闻内容

题目描述编一个程序&#xff0c;读入用户输入的一串先序遍历字符串&#xff0c;根据此字符串建立一个二叉树&#xff08;以指针方式存储&#xff09;。 例如如下的先序遍历字符串&#xff1a; ABC##DE#G##F### 其中“#”表示的是空格&#xff0c;空格字符代表空树。建立起此二叉…...

珠海十大网站建设公司哪家好/东莞网站推广优化网站

这篇不是我想的,是博客园的老赵想的,很是不错.俺就借过来了.原文是您善于使用匿名函数吗&#xff1f; 我只是把重用的地方封装到一个类里面了 public static class CacheHelper { public delegate bool CacheGetter<TData>(out TData data); public delegate TDa…...