javascript - 在javascript中真的需要提升来启用相互递归吗?

标签 javascript recursion mutual-recursion

在一个在线类(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/

相关文章:

javascript - 在同一网页上结合垂直和水平视差滚动

javascript - 使用 AJAX、Javascript/jQuery、DOM 和 Facebook Like 按钮进行无限滚动

coq - 如何定义与函数相互递归的归纳类型?

recursion - 如何使用表示状态的函数在 F# 中获得工作状态机?

coq - Coq最佳实践:相互递归,只有一个函数在结构上递减

javascript - 样式 native JavaScript 通知

javascript - Lottie 动画到达特定帧后如何触发事件?

使用递归的 JavaScript 斐波那契数列

math - 有人可以解释数学归纳法(证明递归方法)

algorithm - 使用递归编程用 L 形三 block 瓷砖填充 n*m block 矩阵的方法数