在一个在线类(class)中,Kyle Simpson 说以下代码演示了在 javascript 中提升的必要性,因为如果不提升“其中一个函数总是被声明为时已晚”。
a(1) // 39
function a(foo){
if (foo > 20) return foo
return b(foo+2)
}
function b(foo){
return c(foo) + 1
}
function c(foo){
return a(foo*2)
}
但这工作得很好。
var a = function(foo){
if (foo > 20) return foo
return b(foo+2)
}
var b = function(foo){
return c(foo) + 1
}
var c = function(foo){
return a(foo*2)
}
a(1) // 39
那么故事是怎样的呢?撇开调用的便利性和位置不谈,是否有任何情况需要提升?
最佳答案
我关于非提升 JS 无法支持相互递归的声明只是出于说明目的的推测。它旨在帮助理解语言了解作用域中可用变量的必要性。这不是针对确切语言行为的处方。
像提升这样的语言特性——实际上提升并不存在,它只是在编译期间、执行之前在作用域环境中提前声明变量的一个隐喻——是一个如此基本的特征,以至于它不容易被当与语言的其他特征分开时进行推理。
此外,仅在 JS 中不可能完全验证这个假设。 OP 中的代码片段仅处理等式的一部分,即它使用函数表达式而不是函数声明来避免函数提升。
我用来比较的语言是 C,例如,它需要在 .h 头文件中声明函数签名,以便编译器知道函数的样子,即使它没有“看到”它然而。没有它,编译器就会窒息。从某种意义上说,这是一种手动吊装。 C 这样做是为了类型检查,但可以想象这种要求的存在是出于其他原因。
另一种思考方式是 JS 是否是一种编译语言,在执行之前一切都已被发现,或者它是否在单次传递中自上而下解释。
如果 JS 是自上而下解释的,它到达了一个 a()
函数的定义,该函数引用了它内部的一个 b()
而它没有还没有看到,这可能是一个问题。如果那个调用表达式是非惰性处理的,那么引擎在那一刻无法弄清楚 b()
调用是关于什么的,因为 b()
没有尚未处理。有些语言是惰性的,有些是非惰性的。
事实上,JS 在执行之前首先被编译,因此引擎在运行任何函数之前已经发现了所有函数(也称为“提升”)。 JS 也将表达式视为惰性的,所以一起解释了为什么相互递归工作正常。
但是如果 JS 没有提升和/或不惰性,可以想象 JS 引擎将无法处理相互递归,因为 a()
和 b( )
实际上意味着两者之一总是被宣布为“太晚了”。
这就是我在书中的全部意思。
关于javascript - 在javascript中真的需要提升来启用相互递归吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36832529/