【问题标题】:What does *exactly* happen during a try catch operation?在 try catch 操作期间*究竟*会发生什么?
【发布时间】:2018-07-18 18:33:50
【问题描述】:

如果您对问题的详细信息不感兴趣,请直接跳至TL/DR


简短的序言:

我最近决定从头开始全面重新学习 JavaScript。 这一次不仅是它是如何工作的,而且是它为什么起作用。一旦您还了解了编译器的工作原理以及所有其他细节,一切都会变得更有意义,问题是有一个预先构建的小表达式:

try.. catch

当它似乎违反了 JS 已有的所有词法和范围规则时,我无法完全理解它为什么起作用。


我没有得到的东西:

不应该打破范围吗?

在这里,我们只使用 2 个级别的范围。
try{ } 内的作用域catch{ } 内的作用域和global 作用域。如果我们要说明这一点,它看起来像这样:

现在两个内部作用域应该充当两个单独的作用域,并且不会相互冲突。考虑到这一点,**try {} 的值怎么会返回到 catch {} 块中,而它应该作为范围包含在自身中。

我什至尝试使用"use strict"; 来查看是否可以以某种方式捕获尝试在块范围之外传递参数的异常,但即便如此.. nada 仍按预期工作:

从技术上讲,我在这里使用function() 创建了一个额外的范围, 不幸的是,没有在 jsfiddle 中使用严格模式是不可能的 自调用函数

(function(){
"use strict";

	try {
          throw 'MadeUpError';
	}

	catch(e) {
		console.log(e);
	}

})();

为什么try {} 块能够将参数传递给catch {} 块,尽管它与strict mode 冲突?

似乎很不合逻辑,当标识符(e) 应该只对它自己的范围是唯一的。

此外,我什至无法从词汇上理解它。 catch 块调用对抛出的异常的不存在索引 (?) 进行右侧查找。
它从哪里以及如何知道它应该从哪里检索异常


TL/DR:

可能回答这个问题最简单的方法是用编译器的伪语言来回答它:例如。

/*
    1. I arrived at try { } block
    2. Created a new Exception
    3. I stored Exception at (?)
    4. Exited try { }
    5. I looked up Exception from ...
*/

希望你能收到我冗长的帖子。我知道这更多是一个理论问题,但我想充分了解try..catch 操作期间幕后发生的事情。

【问题讨论】:

    标签: javascript error-handling try-catch


    【解决方案1】:
    • 我到达try { 块并将其位置推送到try { 块的堆栈上(到达} 时将弹出)*

    • 我执行块内的代码

    • 我到达throw whatever

    • 我将whatever 评估为一个表达式(如果它是一个标识符,我会在当前范围内查找它)

    • 我将评估结果存储在一个临时内部变量中

    • 我从堆栈中查找最上面的try { }并将其弹出

    • 我去相关的catch(identifier) { }区块

    • 我在catch块的作用域内创建identifier,并将内部变量的值复制到其中

    • 我执行了 catch 块

    • 我在catch块之后执行代码

    (这非常简化,甚至在 async 函数内部变得更复杂),您可以在 ECMA 规范的 13.15.7/8 美元阅读整个故事。

    不应该打破范围吗?

    抛出的东西根本不必是try { }s 范围的一部分:

    throw new Error();
    

    它也可以只是表达式的一部分。但是,如果它是范围的一部分:

    const error = new Error();
    throw error; // <- handed over to some internal engine logic
    

    然后抛出它会导致它被复制到作用域之外(到某个内部变量中),作用域将停止存在(随着块停止执行),它将被复制到新作用域的新变量中:

    catch(err) { // <- the error suddenly appears from inside the engine here
    

    所以会有两个作用域有两个变量,但它们的值相同。


    *规范将其定义为块的递归评估,然后将在throw 语句处结束,直到它到达 Try 块,但我认为使用堆栈更容易理解(递归将在结束)。

    【讨论】:

    • @rawrplus 很高兴为您提供帮助 :)
    【解决方案2】:

    (函数(){

    "use strict";
    
        try {
              throw 'MadeUpError';
        }
    
        catch(e) {
            console.log(e);
        }
    
    })();
    

    为什么 try {} 块能够将参数传递给 catch {} 块,尽管它与严格模式冲突?

    把它想象成一种 if/else 块。如果出现错误,则执行 catch 块中的内容。 “e”(错误对象)自动包含在 catch 块中,因为您当然想知道错误是什么。 Javscript 只是将它放在堆栈上并允许您自动引用它

    【讨论】:

      猜你喜欢
      • 2012-03-01
      • 2015-12-25
      • 2013-12-01
      • 2015-10-23
      • 2011-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-12
      相关资源
      最近更新 更多