【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-附录B-严格模式
附录B、严格模式
-
严格模式
- ECMAScript 5 首次引入严格模式的概念。严格模式用于选择以更严格的条件检查 JavaScript 代码错误,可以应用到全局,也可以应用到函数内部。严格模式的好处是可以提早发现错误,因此可以捕获某些 ECMAScript 问题导致的编程错误。
- 理解严格模式的规则非常重要,因为未来的 ECMAScript 会逐步强制全局使用严格模式。严格模式已得到所有主流浏览器支持。
-
选择使用
- 要选择使用严格模式,需要使用严格模式编译指示(pragma),即一个不赋值给任何变量的字符串:
"use strict";
- 这样一个即使在 ECMAScript 3 中也有效的字符串,可以兼容不支持严格模式的 JavaScript 引擎。支持严格模式的引擎会启用严格模式,而不支持的引擎则会将这个编译指示当成一个未赋值的字符串字面量。
- 如果把这个编译指示应用到全局作用域,即函数外部,则整个脚本都会按照严格模式来解析。这意味着在最终会与其他脚本拼接为一个文件的脚本中添加了编译指示,会将该文件中的所有 JavaScript 置于严格模式之下。
- 也可以像下面这样只在一个函数内部开启严格模式:
function doSomething() { "use strict"; // 其他代码 }
- 如果你不能控制页面中的所有脚本,那么建议只在经过测试的特定函数中启用严格模式。
- 要选择使用严格模式,需要使用严格模式编译指示(pragma),即一个不赋值给任何变量的字符串:
-
变量
- 严格模式下如何创建变量及何时会创建变量都会发生变化。第一个变化是不允许意外创建全局变量。在非严格模式下,以下代码可以创建全局变量:
// 变量未声明 // 非严格模式:创建全局变量 // 严格模式:抛出 ReferenceError message = "Hello world!";
- 虽然这里的 message 没有前置 let 关键字,也没有明确定义为全局对象的属性,但仍然会自动创建为全局变量。在严格模式下,给未声明的变量赋值会在执行代码时抛出 ReferenceError。
- 相关的另一个变化是无法在变量上调用 delete。在非严格模式下允许这样,但可能会静默失败(返回 false)。在严格模式下,尝试删除变量会导致错误:
// 删除变量 // 非严格模式:静默失败 // 严格模式:抛出 ReferenceError let color = "red"; delete color;
- 严格模式也对变量名增加了限制。具体来说,不允许变量名为 implements、interface、let、package、private、protected、public、static 和 yield。这些是目前的保留字,可能在将来的 ECMAScript 版本中用到。如果在严格模式下使用这些名称作为变量名,则会导致语法错误。
- 严格模式下如何创建变量及何时会创建变量都会发生变化。第一个变化是不允许意外创建全局变量。在非严格模式下,以下代码可以创建全局变量:
-
对象
- 在严格模式下操作对象比在非严格模式下更容易抛出错误。严格模式倾向于在非严格模式下会静默失败的情况下抛出错误,增加了开发中提前发现错误的可能性。
- 首先,以下几种情况下试图操纵对象属性会引发错误。
- 给只读属性赋值会抛出 TypeError。
- 在不可配置属性上使用 delete 会抛出 TypeError。
- 给不存在的对象添加属性会抛出 TypeError。
- 另外,与对象相关的限制也涉及通过对象字面量声明它们。在使用对象字面量时,属性名必须唯一。例如:
// 两个属性重名 // 非严格模式:没有错误,第二个属性生效 // 严格模式:抛出 SyntaxError let person = { name: "Nicholas", name: "Greg" };
- 这里的对象字面量 person 有两个叫作 name 的属性。第二个属性在非严格模式下是最终的属性。但在严格模式下,这样写是语法错误。
- 注意,ECMAScript 6 删除了对重名属性的这个限制,即在严格模式下重复的对象字面量属性键不会抛出错误。
-
函数
- 首先,严格模式要求命名函数参数必须唯一。看下面的例子:
// 命名参数重名 // 非严格模式:没有错误,只有第二个参数有效 // 严格模式:抛出 SyntaxError function sum (num, num){ // 函数代码 }
- 在非严格模式下,这个函数声明不会抛出错误。这样可以通过名称访问第二个 num,但只能通过arguments 访问第一个参数。
- arguments 对象在严格模式下也有一些变化。在非严格模式下,修改命名参数也会修改 arguments对象中的值。而在严格模式下,命名参数和 arguments 是相互独立的。例如:
// 修改命名参数的值 // 非严格模式:arguments 会反映变化 // 严格模式:arguments 不会反映变化 function showValue(value){ value = "Foo"; alert(value); // "Foo" alert(arguments[0]); // 非严格模式:"Foo" // 严格模式:"Hi" } showValue("Hi");
- 在这个例子中,函数 showValue()有一个命名参数 value。调用这个函数时给它传入参数"Hi",该值会赋给value。在函数内部,value被修改为"Foo"。在非严格模式下,这样也会修改arguments[0]的值,但在严格模式下则不会。
- 另一个变化是去掉了 arguments.callee 和 arguments.caller。在非严格模式下,它们分别引用函数本身和调用函数。在严格模式下,访问这两个属性中的任何一个都会抛出 TypeError。例如:
// 访问 arguments.callee // 非严格模式:没问题 // 严格模式:抛出 TypeError function factorial(num){ if (num <= 1) { return 1; } else { return num * arguments.callee(num-1) } } let result = factorial(5);
- 类似地,读或写函数的 caller 或 callee 属性也会抛出 TypeError。因此对这个例子而言,访问factorial.caller 和 factorial.callee 也会抛出错误。
- 另外,与变量一样,严格模式也限制了函数的命名,不允许函数名为 implements、interface、let、package、private、protected、public、static 和 yield。
- 关于函数的最后一个变化是不允许函数声明,除非它们位于脚本或函数的顶级。这意味着在 if 语句中声明的函数现在是个语法错误:
// 在 if 语句中声明函数 // 非严格模式:函数提升至 if 语句外部 // 严格模式:抛出 SyntaxError if (true){ function doSomething(){ // ... } }
- 首先,严格模式要求命名函数参数必须唯一。看下面的例子:
-
函数参数
- 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"出现在函数体内,JavaScript 解析器就需要在解析函数参数之前先检查函数体内是否存在这个编译指示,而这会带来很多问题。为此,ES7 规范增加了这个约定,目的是让解析器在解析函数之前就确切知道该使用什么模式。
- ES6 增加了剩余操作符、解构操作符和默认参数,为函数组织、结构和定义参数提供了强大的支持。ECMAScript 7 增加了一条限制,要求使用任何上述先进参数特性的函数内部都不能使用严格模式,否则会抛出错误。不过,全局严格模式还是允许的。
-
eval()
- eval()函数在严格模式下也有变化。最大的变化是 eval()不会再在包含上下文中创建变量或函数。例如:
// 使用 eval()创建变量 // 非严格模式:警告框显示 10 // 严格模式:调用 alert(x)时抛出 ReferenceError function doSomething(){ eval("let x = 10"); alert(x); }
- 以上代码在非严格模式下运行时,会在 doSomething()函数内部创建局部变量 x,然后 alert()会显示这个变量的值。在严格模式下,调用 eval()不会在 doSomething()中创建变量 x,由于 x 没有声明,alert()会抛出 ReferenceError。
- 变量和函数可以在 eval()中声明,但它们会位于代码执行期间的一个特殊的作用域里,代码执行完毕就会销毁。因此,以下代码就不会出错:
"use strict"; let result = eval("let x = 10, y = 11; x + y"); alert(result); // 21
- 这里在 eval()中声明了变量 x 和 y,将它们相加后返回得到的结果。变量 result 会包含 x 和 y相加的结果 21,虽然 x 和 y 在调用 alert()时已经不存在了,但不影响结果的显示。
- eval()函数在严格模式下也有变化。最大的变化是 eval()不会再在包含上下文中创建变量或函数。例如:
-
eval 与 arguments
- 严格模式明确不允许使用 eval 和 arguments 作为标识符和操作它们的值。例如:
// 将 eval 和 arguments 重新定义为变量 // 非严格模式:可以,没有错误 // 严格模式:抛出 SyntaxError let eval = 10; let arguments = "Hello world!";
- 在非严格模式下,可以重写 eval 和 arguments。在严格模式下,这样会导致语法错误。不能用它们作为标识符,这意味着下面这些情况都会抛出语法错误:
- 使用 let 声明;
- 赋予其他值;
- 修改其包含的值,如使用++;
- 用作函数名;
- 用作函数参数名;
- 在 try/catch 语句中用作异常名称。
- 严格模式明确不允许使用 eval 和 arguments 作为标识符和操作它们的值。例如:
-
this 强制转型
- JavaScript 中最大的一个安全问题,也是最令人困惑的一个问题,就是在某些情况下 this 的值是如何确定的。使用函数的 apply()或 call()方法时,在非严格模式下 null 或 undefined 值会被强制转型为全局对象。在严格模式下,则始终以指定值作为函数 this 的值,无论指定的是什么值。例如:
// 访问属性 // 非严格模式:访问全局属性 // 严格模式:抛出错误,因为 this 值为 null let color = "red"; function displayColor() { alert(this.color); } displayColor.call(null);
- 这里在调用 displayColor.call()时传入 null 作为 this 的值,在非严格模式下该函数的 this值是全局对象。结果会显示"red"。在严格模式下,该函数的 this 值是 null,因此在访问 null 的属性时会抛出错误。
- 通常,函数会将其 this 的值转型为一种对象类型,这种行为经常被称为“装箱”(boxing)。这意味着原始值会转型为它们的包装对象类型。
function foo() { console.log(this); } foo.call(); // Window {} foo.call(2); // Number {2}
- 在严格模式下执行以上代码时,this 的值不会再“装箱”:
function foo() { "use strict"; console.log(this); } foo.call(); // undefined foo.call(2); // 2
- JavaScript 中最大的一个安全问题,也是最令人困惑的一个问题,就是在某些情况下 this 的值是如何确定的。使用函数的 apply()或 call()方法时,在非严格模式下 null 或 undefined 值会被强制转型为全局对象。在严格模式下,则始终以指定值作为函数 this 的值,无论指定的是什么值。例如:
-
类与模块
- 类和模块都是 ECMAScript 6 新增的代码容器特性。在之前的 ECMAScript 版本中没有类和模块这两个概念,因此不用考虑从语法上兼容之前的 ECMAScript 版本。为此,TC39 委员会决定在 ES6 类和模块中定义的所有代码默认都处于严格模式。
- 对于类,这包括类声明和类表达式,构造函数、实例方法、静态方法、获取方法和设置方法都在严格模式下。对于模块,所有在其内部定义的代码都处于严格模式。
-
其他变化
- 严格模式下还有其他一些需要注意的变化。首先是消除 with 语句。with 语句改变了标识符解析时的方式,严格模式下为简单起见已去掉了这个语法。在严格模式下使用 with 会导致语法错误:
// 使用 with 语句 // 非严格模式:允许 // 严格模式:抛出 SyntaxError with(location) { alert(href); }
- 严格模式也从 JavaScript 中去掉了八进制字面量。八进制字面量以前导 0 开始,一直以来是很多错误的源头。在严格模式下使用八进制字面量被认为是无效语法:
// 使用八进制字面量 // 非严格模式:值为 8 // 严格模式:抛出 SyntaxError let value = 010;
- ECMAScript 5修改了非严格模式下的parseInt(),将八进制字面量当作带前导0的十进制字面量。例如:
// 在 parseInt()中使用八进制字面量 // 非严格模式:值为 8 // 严格模式:值为 10 let value = parseInt("010");
- 严格模式下还有其他一些需要注意的变化。首先是消除 with 语句。with 语句改变了标识符解析时的方式,严格模式下为简单起见已去掉了这个语法。在严格模式下使用 with 会导致语法错误:
相关文章:
【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-附录B-严格模式
附录B、严格模式 严格模式 ECMAScript 5 首次引入严格模式的概念。严格模式用于选择以更严格的条件检查 JavaScript 代码错误,可以应用到全局,也可以应用到函数内部。严格模式的好处是可以提早发现错误,因此可以捕获某些 ECMAScript 问题导致…...
跨平台 C++ 程序崩溃调试与 Dump 文件分析
前言 C 程序在运行时可能会由于 空指针访问、数组越界、非法内存访问、栈溢出 等原因崩溃。为了分析崩溃原因,我们通常会生成 Dump 文件(Windows 的 .dmp,Linux 的 core,macOS 的 .crash),然后用调试工具分…...
缺陷VS质量:为何软件缺陷是质量属性的致命对立面?
为何说缺陷是质量的对立面? 核心逻辑:软件质量的定义是“满足用户需求的程度”,而缺陷会直接破坏这种满足关系。 对立性:缺陷的存在意味着软件偏离了预期行为(如功能错误、性能不足、安全性漏洞等)&#…...
伍[5],伺服电机,电流环,速度环,位置环
电流环、速度环和位置环是电机控制系统中常见的三个闭环控制环节,通常采用嵌套结构(内环→外环:电流环→速度环→位置环),各自负责不同层级的控制目标。以下是它们的详细说明及相互关系: 1. 电流环(最内环) 作用:控制电机的电流,间接控制输出转矩(τ=Kt⋅Iτ=Kt⋅…...

RuntimeError: CUDA error: device-side assert triggered
RuntimeError: CUDA error: device-side assert triggered 欢迎来到英杰社区,这里是博主英杰https://bbs.csdn.net/topics/617804998 原因: cuda运行可能是异步的(asynchronously),因此报错信息中提示的位置可能不准确…...
清华大学Deepseek第六版AIGC发展研究3.0(共186页,附PDF下载)
人工智能生成内容(AIGC)正以前所未有的速度改变我们的生活。 2024年底,清华大学新闻与传播学院与人工智能学院联合发布了《AIGC发展研究3.0版》,这份报告系统梳理了AIGC技术的突破性进展、应用场景及社会影响,并展望了…...
SpringBoot生成唯一ID的方式
1.为什么要生成唯一ID? 数据唯一性:每个记录都需要有一个独一无二的标识符来确保数据的唯一性。这可以避免重复的数据行,并有助于准确地查询、更新或删除特定的记录。 数据完整性:通过使用唯一ID,可以保证数据库中的数…...
通俗易懂的分类算法之K近邻详解
通俗易懂的分类算法之K近邻详解 用最通俗的语言和例子,来彻底理解 K近邻(K-Nearest Neighbors,简称 KNN) 这个分类算法。不用担心复杂的数学公式,我会用生活中的例子来解释,保证你一听就懂! 1.…...
CSDN markdown 操作指令等
CSDN markdown 操作指令等 页内跳转 [内容](#1) <div id"1"> </div>...
【linux】文件与目录命令 - uniq
文章目录 1. 基本用法2. 常用参数3. 用法举例4. 注意事项 uniq 命令用于过滤文本文件中相邻的重复行,并支持统计重复次数或仅保留唯一行。它通常与 sort 命令配合使用,因为 uniq 只识别相邻的重复行。 1. 基本用法 语法: uniq [选项] [输入…...

零信任沙箱:为网络安全筑牢“隔离墙”
在数字化浪潮汹涌澎湃的今天,网络安全如同一艘船在波涛汹涌的大海中航行,面临着重重挑战。数据泄露、恶意软件攻击、网络钓鱼等安全威胁层出不穷,让企业和个人用户防不胜防。而零信任沙箱,就像是一座坚固的“隔离墙”,…...
【金融量化】Ptrade中交易环境支持的业务类型
1. 普通股票买卖 • 特点: 普通股票买卖是最基础的交易形式,投资者通过买入和卖出上市公司的股票来获取收益。 ◦ 流动性高:股票市场交易活跃,买卖方便。 ◦ 收益来源多样:包括股价上涨的资本利得和公司分红。 ◦ 风险…...

【Java---数据结构】链表 LinkedList
1. 链表的概念 链表用于存储一系列元素,由一系列节点组成,每个节点包含两部分:数据域和指针域。 数据域:用于存储数据元素 指针域:用于指向下一个节点的地址,通过指针将各个节点连接在一起,形…...
紧跟 Web3 热潮,RuleOS 如何成为行业新宠?
Web3 热潮正以汹涌之势席卷全球。从金融领域的创新应用到供应链管理的变革,从社交媒体的去中心化尝试到游戏产业的全新玩法探索,Web3 凭借其去中心化、安全性和用户赋权等特性,为各个行业带来了前所未有的机遇。在这股热潮中,Rule…...

CC++的内存管理
目录 1、C/C内存划分 C语言的动态内存管理 malloc calloc realloc free C的动态内存管理 new和delete operator new函数和operator delete函数 new和delete的原理 new T[N]原理 delete[]的原理 1、C/C内存划分 1、栈:存有非静态局部变量、函数参数、返回…...

Spark核心之02:RDD、算子分类、常用算子
spark内存计算框架 一、目标 深入理解RDD弹性分布式数据集底层原理掌握RDD弹性分布式数据集的常用算子操作 二、要点 ⭐️1. RDD是什么 RDD(Resilient Distributed Dataset)叫做**弹性分布式数据集,是Spark中最基本的数据抽象,…...

【Resis实战分析】Redis问题导致页面timeout知识点分析
事故现象:前端页面返回timeout 事故回溯总结一句话: (1)因为大KEY调用量,随着白天自然流量趋势增长而增长,最终在业务高峰最高点期占满带宽使用100%。   (2&#x…...
单一职责原则(设计模式)
目录 问题: 定义: 解决: 方式 1:使用策略模式 示例:用户管理 方式 2:使用装饰者模式 示例:用户操作 方式 3:使用责任链模式 示例:用户操作链 总结 推荐 问题&a…...
生理信号概念
rPPG 信号(远程光电容积脉搏波信号) 原理: 基于光电容积脉搏波描记法,利用普通摄像头,在一定距离外捕捉人体皮肤表面因心脏泵血导致的血液容积变化引起的细微颜色变化,通过图像处理和信号分析算法提取心率…...

安卓内存泄露之DMA-BUF异常增长:Android Studio镜像引起DMA内存泄露
安卓内存泄露之DMA-BUF异常增长:Android Studio镜像引起DMA内存泄露 - Wesley’s Blog 今天用着安卓 14 的板子的时候突然系统卡死。 查看日志发现launcher都被干掉了 03-04 06:13:35.544 7872 8479 I ActivityManager: vis BFGS 18740: com.android.launcher3 (pid 8407) se…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...

【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...