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

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

C++:多态机制详解

目录 一. 多态的概念 1.静态多态&#xff08;编译时多态&#xff09; 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1&#xff09;.协变 2&#xff09;.析构函数的重写 5.override 和 final关键字 1&#…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下&#xff1a; avformat_open_input 精简后的代码如下&#xff1a; int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...