JavaScript: 函数执行顺序

JavaScript: ORDER of function execution

我正在学习JavaScript,但是有很多东西我不能理解。在一次在线 JavaScript 测验中,出现了以下问题:
以下 JavaScript 代码将什么记录到控制台:

const a = {};
const b = () => a.a = () => {};
const c = c => '' + c + a.a(b());
const d = console.log.bind(console);
const e = (e => () => d(c(e++)))(0);

try{
  e();
}catch(a){
  e();
}

我花了一些时间才理解每个变量(这里是常量)代表什么。我开始分析 try 块内 e() 的代码。所以,e 代表一个闭包,这意味着函数 d 将以参数 c(0) 被调用,并且 e 将变为 1。据我了解,这里的d基本上代表了console.log的功能(但我想不通为什么要用bind?)。

现在,我知道首先会执行 c(0) 然后将结果记录到控制台,对吗?让我们看一下函数 c。它 returns 第一个参数转换为字符串和 a.a(b()) 的连接结果。好的,所以 a.a(b()) 将首先执行,对吗?但是,问题是因为 a.a 不是函数,它是未定义的,所以会抛出错误,我们转到 catch.

现在,在 catch 块中,一切都应该是一样的,所以 a.a 仍然不是函数,应该抛出引用错误。但是,当我看到没有抛出任何错误,但控制台实际上记录 1undefined 时,我感到很惊讶。为什么?怎么样?

好吧,经过一番思考,我意识到也许在调用a.a(b())时可能会先执行b()。按照我的假设,然后函数 b 将引用分配给一个对对象 a 的 属性 a 没有任何作用的函数,对吗?但是,然后 a.a 是一个函数,它将在 try 块中执行,并且 0undefined 将被记录。

然而,这两个假设中none是正确的。这里的主要问题是先执行什么?如果我们调用 someObject.propertyWhichIsNotAFunction(somethingWhichMakesItAFunction),会发生什么?首先执行什么?似乎在 try 块中先执行一件事,在 catch 中先执行另一件事。这对我来说真的毫无意义。有什么解释吗?

这与 Why is the value of foo.x undefined in foo.x = foo = {n: 2}? 的原因非常相似,只是有点棘手,因为它依赖于在执行中何时抛出 TypeError。

基本上发生的事情是:

    计算
  1. a.a 以确定稍后在步骤 3.
  2. 中将调用哪个函数
  3. b() 被评估,因为它是一个函数参数及其 return value 成为 a.a 计算结果的实际参数。
  4. 在第 1 步中计算出的任何 a.a 都会以 b() 的 return 值作为其参数执行。

规范的相关部分在这里:https://www.ecma-international.org/ecma-262/7.0/index.html#sec-function-calls

请注意,调用函数时发生的第一件事是:

  1. Let ref be the result of evaluating MemberExpression.
  2. Let func be ? GetValue(ref).

这意味着a.a被求值,它所指的函数被称为func。第一次 a.a 的计算结果为 undefined,因此 funcundefined 并且将在 https://www.ecma-international.org/ecma-262/7.0/index.html#sec-evaluatedirectcall 的第 2 步抛出 TypeError,即 after ArgumentListEvaluation(arguments),它调用 b() 并将新值分配给 a.a,但不在值之后func.