如果您对问题的详细信息不感兴趣,可以直接跳至TL/DR
我最近决定完全重新学习JavaScript。 这次不仅是如何运作的,而且还有它为什么运作的。一旦您还了解了编译器的工作方式以及所有其他细腻的细节,一切都会变得更加有意义,问题是有一个小的预构建表达式:
当它似乎违反了JS的所有词法和作用域规则时,我还无法确定它为什么起作用。
这不应该超出范围吗?
在这里,我们仅在两个级别的范围内工作。
try{ }
内的范围和catch{ }
内的范围。如果我们要说明这一点,它将看起来像这样:
现在,两个内部作用域应充当两个单独的作用域,而不应彼此冲突。考虑到这一点,** global
的值如何返回到try {}
块中,而应将其作为范围包含在自身中。
我什至尝试使用catch {}
来查看是否能以某种方式捕获试图在块范围之外传递参数的异常,但即使那样.. nada仍能按预期工作:
从技术上讲,我在这里使用
"use strict";
创建了一个额外的范围, 不幸的是,如果没有 自我调用功能
function()
尽管(function(){
"use strict";
try {
throw 'MadeUpError';
}
catch(e) {
console.log(e);
}
})();
块与try {}
发生冲突,但为什么catch {}
块才能将参数传递给strict mode
? >
当标识符(e)
仅对其自己的作用域唯一时,似乎很不合逻辑。
此外,我什至无法从词汇上理解它。
catch块要求对抛出的异常不存在的索引(?)进行右侧查找。
从何处以及如何知道应该从何处检索异常?
回答这个问题的最简单方法可能是以编译器的伪语言来回答它,例如:
/*
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
操作期间幕后发生的事情。
答案 0 :(得分:2)
我到达try {
块并将其位置推到try {
块堆栈中(到达}
时会弹出)*
我在块内执行代码
我到达了throw whatever
我将whatever
评估为表达式(如果它是一个标识符,我会在当前范围内查找它)
我将评估结果存储在一个临时内部变量中
我从堆栈中查找最高的try { }
并将其弹出
我进入相关的catch(identifier) { }
街区
我在catch块的范围内创建了identifier
,并将内部变量的值复制到其中
我执行catch块
我在catch块之后执行代码
(这非常简化,它甚至在async
函数中变得更加复杂),您可以按ECMA规范的$ 13.15.7 / 8阅读全部内容。
这不应该超出范围吗?
抛出的东西根本不必成为try { }
范围的一部分:
throw new Error();
它也可以只是表达式的一部分。但是,如果它属于以下范围:
const error = new Error();
throw error; // <- handed over to some internal engine logic
然后将其抛出将导致将其复制到范围之外(复制到某个内部变量中),该范围将停止存在(因为该块停止执行),并将其复制到一个新范围的新变量中: / p>
catch(err) { // <- the error suddenly appears from inside the engine here
所以会有两个带两个变量的作用域,但是它们具有相同的值。
** Spec将其定义为对块的递归评估,然后将在throw
语句中结束直到到达Try块,但我认为使用堆栈更容易理解(该递归将是最后)。
答案 1 :(得分:0)
(function(){
"use strict";
try {
throw 'MadeUpError';
}
catch(e) {
console.log(e);
}
})();
try {}块如何能够将参数传递给catch {} 阻止,尽管事实与严格模式冲突?
将其视为一种if / else块。如果出现错误,则执行catch块中的内容。 catch块中将自动包含“ e”(错误对象),因为您当然想知道错误是什么。 Javscript只是将其放在堆栈上,并允许您自动引用它