代码之家  ›  专栏  ›  技术社区  ›  Samuel Hulla

在Try-Catch操作期间,*确切地*发生了什么?

  •  3
  • Samuel Hulla  · 技术社区  · 7 年前

    可以直接跳到 TL/DR 如果你对这个问题的细节不感兴趣


    前言:

    我最近决定从头开始全面重新学习javascript。 这一次,不仅是它的工作方式,也是它工作的原因。一旦您了解了编译器的工作原理和所有其他细节,一切都变得更有意义,问题是有一个小的预构建表达式:

    try.. catch

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


    我没有得到的东西:

    它不应该打破范围吗?

    这里我们只使用两个级别的范围。
    里面的范围 try{ } 里面的范围 catch{ } 以及 global 范围。如果我们要说明这一点,它看起来应该是这样的:

    enter image description here

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

    我甚至试着用 "use strict"; 看看我是否能捕捉到一个异常,尝试在块范围之外传递参数,但即使是这样……纳达,按预期工作:

    从技术上讲,我在这里用 function() , 不幸的是,在JSfiddle中使用严格模式是不可能的。 自调用函数

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

    为什么 尝试{} 块能够将参数传递给 捕获 块,尽管它与 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 操作。

    2 回复  |  直到 7 年前
        1
  •  2
  •   Jonas Wilms    7 年前
    • 我到了 try { 阻止并将其位置推到 尝试{ 块(当 } 已到达)*

    • 我在块内执行代码

    • 我到达一个 throw whatever

    • 我评估 whatever 作为表达式(如果它是标识符,我会在当前作用域中查找它)

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

    • 我往上看 try { } 从堆栈中弹出

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

    • 我创造了 identifier 在catch块的范围内,并将内部变量的值复制到它

    • 我执行catch块

    • 我在catch块后执行代码

    (这是非常简单的,它甚至在 async 函数),您可以在ECMA规范的13.15.7/8美元处阅读整个故事。

    它不应该打破范围吗?

    扔的东西不一定是 试试 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块,但是我认为用一个堆栈更容易理解(递归将在末尾)。

        2
  •  0
  •   ControlAltDel    7 年前

    (函数()。{

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

    Try块如何能够向catch传递参数 阻止,尽管它与严格模式冲突?

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