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。
基本上发生的事情是:
计算 a.a
以确定稍后在步骤 3. 中将调用哪个函数
b()
被评估,因为它是一个函数参数及其 return
value 成为 a.a
计算结果的实际参数。
- 在第 1 步中计算出的任何
a.a
都会以 b()
的 return 值作为其参数执行。
规范的相关部分在这里:https://www.ecma-international.org/ecma-262/7.0/index.html#sec-function-calls
请注意,调用函数时发生的第一件事是:
- Let ref be the result of evaluating MemberExpression.
- Let func be ? GetValue(ref).
这意味着a.a
被求值,它所指的函数被称为func
。第一次 a.a
的计算结果为 undefined
,因此 func
为 undefined
并且将在 https://www.ecma-international.org/ecma-262/7.0/index.html#sec-evaluatedirectcall 的第 2 步抛出 TypeError,即 after ArgumentListEvaluation(arguments)
,它调用 b()
并将新值分配给 a.a
,但不在值之后func
.
我正在学习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。
基本上发生的事情是:
-
计算
a.a
以确定稍后在步骤 3. 中将调用哪个函数
b()
被评估,因为它是一个函数参数及其 return value 成为a.a
计算结果的实际参数。- 在第 1 步中计算出的任何
a.a
都会以b()
的 return 值作为其参数执行。
规范的相关部分在这里:https://www.ecma-international.org/ecma-262/7.0/index.html#sec-function-calls
请注意,调用函数时发生的第一件事是:
- Let ref be the result of evaluating MemberExpression.
- Let func be ? GetValue(ref).
这意味着a.a
被求值,它所指的函数被称为func
。第一次 a.a
的计算结果为 undefined
,因此 func
为 undefined
并且将在 https://www.ecma-international.org/ecma-262/7.0/index.html#sec-evaluatedirectcall 的第 2 步抛出 TypeError,即 after ArgumentListEvaluation(arguments)
,它调用 b()
并将新值分配给 a.a
,但不在值之后func
.