首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >JavaScript中在try里面放return,finally还会执行吗?

JavaScript中在try里面放return,finally还会执行吗?

作者头像
越陌度阡
发布于 2022-11-27 09:54:14
发布于 2022-11-27 09:54:14
1.1K04
代码可运行
举报
运行总次数:4
代码可运行

在前面几篇文章中,我们已经了解了关于执行上下文、作用域、闭包之间的关系。

今天,我们则要说一说更为细节的部分:语句。

语句是任何编程语言的基础结构,与 JavaScript 对象一样,JavaScript 语句同样具有“看起来很像其它语言,但是其实一点都不一样”的特点。

我们比较常见的语句包括变量声明、表达式、条件、循环等,这些都是大家非常熟悉的东西,对于它们的行为,我在这里就不赘述了。

为了了解 JavaScript 语句有哪些特别之处,首先我们要看一个不太常见的例子,我会通过这个例子,来向你介绍 JavaScript 语句执行机制涉及的一种基础类型:Completion 类型。

1. Completion 类型

我们来看一个例子。在函数 foo 中,使用了一组 try 语句。我们可以先来做一个小实验,在 try 中有 return 语句,finally 中的内容还会执行吗?我们来看一段代码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function foo() {
    try {
        return 0;
    } catch (err) {

    } finally {
        console.log("a")
    }
}

console.log(foo());

通过实际试验,我们可以看到,finally 确实执行了,而且 return 语句也生效了,foo() 返回了结果 0。

虽然 return 执行了,但是函数并没有立即返回,又执行了 finally 里面的内容,这样的行为违背了很多人的直觉。

如果在这个例子中,我们在 finally 中加入 return 语句,会发生什么呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function foo() {
    try {
        return 0;
    } catch (err) {

    } finally {
        return 1;
    }
}

console.log(foo());

通过实际执行,我们看到,finally 中的 return “覆盖”了 try 中的 return。在一个函数中执行了两次 return,这已经超出了很多人的常识,也是其它语言中不会出现的一种行为。

面对如此怪异的行为,我们当然可以把它作为一个孤立的知识去记忆,但是实际上,这背后有一套机制在运作。

这一机制的基础正是 JavaScript 语句执行的完成状态,我们用一个标准类型来表示:Completion Record(我在类型一节提到过,Completion Record 用于描述异常、跳出等语句执行过程)。

Completion Record 表示一个语句执行完之后的结果,它有三个字段:

1. [[type]] 表示完成的类型,有 break continue return throw 和 normal 几种类型;

2. [[value]] 表示语句的返回值,如果语句没有,则是 empty;

3. [[target]] 表示语句的目标,通常是一个 JavaScript 标签(标签在后文会有介绍)。

JavaScript 正是依靠语句的 Completion Record 类型,方才可以在语句的复杂嵌套结构中,实现各种控制。接下来我们要来了解一下 JavaScript 使用 Completion Record 类型,控制语句执行的过程。

首先我们来看看语句有几种分类。

2. 普通的语句

在 JavaScript 中,我们把不带控制能力的语句称为普通语句。普通语句有下面几种:

1. 声明类语句;

(1). var 声明;

(2). const 声明;

(3). let 声明;

(4). 函数声明;

(5). 类声明;

2. 表达式语句;

3. 空语句;

4. debugger 语句;

这些语句在执行时,从前到后顺次执行(我们这里先忽略 var 和函数声明的预处理机制),没有任何分支或者重复执行逻辑。

普通语句执行后,会得到 [[type]] 为 normal 的 Completion Record,JavaScript 引擎遇到这样的 Completion Record,会继续执行下一条语句。

这些语句中,只有表达式语句会产生 [[value]],当然,从引擎控制的角度,这个 value 并没有什么用处。

如果你经常使用 Chrome 自带的调试工具,可以知道,输入一个表达式,在控制台可以得到结果,但是在前面加上 var,就变成了 undefined。

Chrome 控制台显示的正是语句的 Completion Record 的[[value]]。

3. 语句块

介绍完了普通语句,我们再来介绍一个比较特殊的语句:语句块。

语句块就是拿大括号括起来的一组语句,它是一种语句的复合结构,可以嵌套。

语句块本身并不复杂,我们需要注意的是语句块内部的语句的 Completion Record 的[[type]] 如果不为 normal,会打断语句块后续的语句执行。

比如我们考虑,一个[[type]]为 return 的语句,出现在一个语句块中的情况。

从语句的这个 type 中,我们大概可以猜到它由哪些特定语句产生,我们就来说说最开始的例子中的 return。

return 语句可能产生 return 或者 throw 类型的 Completion Record。

我们来看一个例子,先给出一个内部为普通语句的语句块:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
    var i = 1;      // normal, empty, empty
    i++;            // normal, 1, empty
    console.log(i)  //normal, undefined, empty
} 
// normal, undefined, empty

在每一行的注释中,我给出了语句的 Completion Record。

我们看到,在一个 block 中,如果每一个语句都是 normal 类型,那么它会顺次执行。接下来我们加入 return 试试看。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
    var i = 1;     // normal, empty, empty
    return i;      // return, 1, empty
    i++;
    console.log(i)
} 
// return, 1, empty

但是假如我们在 block 中插入了一条 return 语句,产生了一个非 normal 记录,那么整个 block 会成为非 normal。这个结构就保证了非 normal 的完成类型可以穿透复杂的语句嵌套结构,产生控制效果。

接下来我们就具体讲讲控制类语句。

4. 控制型语句

控制型语句带有 if、switch 关键字,它们会对不同类型的 Completion Record 产生反应。

控制类语句分成两部分,一类是对其内部造成影响,如 if、switch、while/for、try。

另一类是对外部造成影响如 break、continue、return、throw,这两类语句的配合,会产生控制代码执行顺序和执行逻辑的效果,这也是我们编程的主要工作。

一般来说, for/while - break/continue 和 try - throw 这样比较符合逻辑的组合,是大家比较熟悉的,但是,实际上,我们需要控制语句跟 break 、continue 、return 、throw 四种类型与控制语句两两组合产生的效果。

通过这个表,我们不难发现知识的盲点,也就是我们最初的的 case 中的 try 和 return 的组合了。

因为 finally 中的内容必须保证执行,所以 try/catch 执行完毕,即使得到的结果是非 normal 型的完成记录,也必须要执行 finally。

而当 finally 执行也得到了非 normal 记录,则会使 finally 中的记录作为整个 try 结构的结果。

5. 带标签的语句

前文我重点讲了 type 在语句控制中的作用,接下来我们重点来讲一下最后一个字段:target,这涉及了 JavaScript 中的一个语法,带标签的语句。

实际上,任何 JavaScript 语句是可以加标签的,在语句前加冒号即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
firstStatement: var i = 1;

大部分时候,这个东西类似于注释,没有任何用处。唯一有作用的时候是:与完成记录类型中的 target 相配合,用于跳出多层循环。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
outer: while(true) {
    inner: while(true) {
        break outer;
    }
}
console.log("finished")

break/continue 语句如果后跟了关键字,会产生带 target 的完成记录。一旦完成记录带了 target,那么只有拥有对应 label 的循环语句会消费它。

6. 结语

我们以 Completion Record 类型为线索,为你讲解了 JavaScript 语句执行的原理。

因为 JavaScript 语句存在着嵌套关系,所以执行过程实际上主要在一个树形结构上进行, 树形结构的每一个节点执行后产生 Completion Record,根据语句的结构和 Completion Record,JavaScript 实现了各种分支和跳出逻辑。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-07-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
一文带你解读​JavaScript的基本用法
相信做网站对JavaScript再熟悉不过了,它是一门脚本语言,不同于Python的是,它是一门浏览器脚本语言,而Python则是服务器脚本语言,我们不光要会Python,还要会JavaScript,因为它对做网页方面是有很大作用的。
前端皮皮
2021/10/20
3400
细数 JavaScript 实用黑科技(一)
从接触前端开发到现在已经将近 2 年了,最近又看了阮一锋写的: 《JavaScript 语言入门教程》 一书,重温 JavaScript 。
夜尽天明
2019/11/13
7970
细数 JavaScript 实用黑科技(一)
《你不知道的JavaScript》 (中) 阅读摘要
本书属于基础类书籍,会有比较多的基础知识,所以这里仅记录平常不怎么容易注意到的知识点,不会全记,供大家和自己翻阅;
前端下午茶
2019/06/27
9150
重学JS基础-词法和语法
注意和是 ES5 新加入的两个格式控制字符,它们都是 0 宽的。即length长度为0,也称为0宽非连接符和0宽连接符
Jou
2022/08/10
1.4K0
JavaScript基础
脚本语言,语法类似于java(脚本语言又被称为扩建的语言,或者动态语言,是一种编程语言,用来控制软件应用程序,脚本通常以文本(如ASCII)保存,只在被调用时进行解释或编译。)
xiaozhangStu
2023/05/04
4750
【深扒】深入理解 JavaScript 中的生成器
在上篇文章中,我们深入了理解了迭代器的原理和作用,这一篇我们来深扒与迭代器息息相关的生成器。
小丞同学
2021/08/16
3740
从 ECMAScript 6 角度谈谈执行上下文
起因是最近了解JS执行上下文的时候,发现很多书籍和资料,包括《JavaScript高级程序设计》、《JavaScript权威指南》和网上的一些博客专栏,都是从 ES3 角度来谈执行上下文,用ES6规范解读的比较少,所以想从ES6的角度看一下执行上下文。
归思君
2023/12/22
2500
从 ECMAScript 6 角度谈谈执行上下文
大话 JavaScript(Speaking JavaScript):第一章到第五章
这部分是 JavaScript 的一个独立快速介绍。你可以在不阅读本书中的其他内容的情况下理解它,本书的其他部分也不依赖于它的内容。然而,阅读本书的提示在阅读本书的提示中适用。
ApacheCN_飞龙
2024/01/12
6190
大话 JavaScript(Speaking JavaScript):第一章到第五章
大话 JavaScript(Speaking JavaScript):第十一章到第十五章
JavaScript 对所有数字都使用单一类型:它将它们全部视为浮点数。但是,如果小数点后没有数字,则不显示小数点:
ApacheCN_飞龙
2024/01/12
9110
一篇文章带你了解JavaScript中的语法,数据类型,流程控制语句以及函数
JavaScript有多重要啊,才能让我说说一下,其中的语法,操作符,数据类型,内置功能等。
达达前端
2019/12/26
6370
一篇文章带你了解JavaScript中的语法,数据类型,流程控制语句以及函数
【JS】1400- 6 个意想不到的 JavaScript 问题
作为前端开发工程师,JavaScript 是我们的主要开发语言,它本身语法比较简单,并且生态系统也非常完善,在社区的影响力越来越大。
pingan8787
2022/11/15
5140
【JS】1400- 6 个意想不到的 JavaScript 问题
javaScript的基本语法大全
JavaScript 程序的执行单位为行(line),也就是一行一行地执行。一般情况下,每一行就是一个语句。语句(statement)是为了完成某种任务而进行的操作,比如下面就是一行赋值语句。
Java深度编程
2020/06/10
1.4K0
javaScript的基本语法大全
JavaScript中break、continue和return的区别
break: 直接跳出 当前 的循环,从当前循环外面开始执行,忽略循环体中任何其他语句和循环条件测试。它只能跳出一层循环,如果你的循环是嵌套循环,那么你需要按照你嵌套的层次,逐步使用break来跳出。
TimothyJia
2019/11/12
1.5K0
送你43道JavaScript面试题
这两天的GitHub Trending repositories被一个名叫 javascript-questions的项目霸榜了,项目中记录了一些JavaScript题目。
Nealyang
2019/09/29
1.7K0
送你43道JavaScript面试题
前端学习之JavaScript
尽管 ECMAScript 是一个重要的标准,但它并不是 JavaScript 唯一的部分,当然,也不是唯一被标准化的部分。实际上,一个完整的 JavaScript 实现是由以下 3 个不同部分组成的:
超蛋lhy
2018/08/31
1.8K0
前端学习之JavaScript
JavaScript控制语句
控制流语句通过使用决策、循环和分支来分解执行流。JavaScript支持的决策语句(if、if-else、switch)、循环语句(for、while、do-while)和分支语句(break、continue、return)。
zy010101
2022/06/28
6590
JavaScript
JavaScript是一门编程语言,浏览器内置了JavaScript语言的解释器,所以在浏览器上按照JavaScript语言的规则编写相应的代码,浏览器可以解释并作出相应的处理。
Wyc
2018/09/11
1.2K0
JavaScript Standard Style(JS Standard 代码风格规则详解)
现在所有流行的代码压缩器都是通过 AST 压缩,因此它们在处理没有分号的 JavaScript 代码时没有问题(因为 JavaScript 不是必须使用分号)。
FungLeo
2019/05/26
3K0
JavaScript基础笔记
摘要: 1.语句 2.变量 2.1变量提升 3.标识符 4.注释 5.区块 6.条件语句 6.1 if 结构 6.2 if…else结构 6.3 switch结构 6.4三元运算
小胖
2018/06/27
1.3K0
JS的控制流程
通过var声明的变量没有块级作用域。在语句块里声明的变量作用域是其所在的函数或者 script 标签内,你可以在语句块外面访问到它。换句话说,语句块 不会生成一个新的作用域。尽管单独的语句块是合法的语句,但在JavaScript中你不会想使用单独的语句块,因为它们不像你想象的C或Java中的语句块那样处理事物。例如:
acc8226
2022/05/17
8.3K0
相关推荐
一文带你解读​JavaScript的基本用法
更多 >
领券
一站式MCP教程库,解锁AI应用新玩法
涵盖代码开发、场景应用、自动测试全流程,助你从零构建专属AI助手
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档