在一个在线课程中,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
那么故事是什么?除了调用的便利性和位置,是否存在要求提升的情况?
答案 0 :(得分:4)
除了调用的便利性和位置外,没有任何需要吊装的情况。
请确保在使用之前声明所有功能。
注意:在某些浏览器中,function a(){}
会创建名为a
的函数,而var a = function(){}
则不会创建(被视为匿名函数)。调试时使用函数名称。您也可以var b = function a(){}
。
答案 1 :(得分:2)
我所提出的关于一个不提升的JS无法支持相互递归的说法只是用于说明目的的推测。它旨在帮助理解语言需要了解范围内可用的变量。这不是确切语言行为的处方。
像提升一样的语言特征 - 实际上不存在,它只是在编译期间,在执行之前提前在范围环境中声明变量的隐喻 - 这是一个基本的特征,它不容易被当与语言的其他特征分开时,推理出来。
另外,仅仅在JS中完全测试这个假设是不可能的。 OP中的片段仅处理等式的一部分,即它使用函数表达式而不是函数声明来避免函数提升。
我用来比较插图的语言是C,例如要求在.h头文件中声明函数签名,以便编译器知道函数的外观,即使它没有“看到”它然而。没有它,编译器就会窒息。从某种意义上说,这是一种手动吊装。 C用于类型检查,但可以想象这种要求存在的原因不同于其他原因。
另一种思考方式是JS是一种编译语言,在执行之前已经发现了所有内容,或者它是否在一次传递中被自上而下解释。
如果JS是自上而下解释的,并且它得到了a()
函数的定义,该函数在其中引用了它尚未见过的b()
,那可能是个问题。如果该调用表达式是非延迟处理的,那么引擎无法确定b()
调用的内容,因为b()
尚未处理。有些语言是懒惰的,有些是非懒惰的。
原样,JS在执行之前首先编译,因此引擎在运行任何函数之前已经发现了所有函数(也就是“提升”)。 JS也将表达式视为惰性,因此可以解释为什么相互递归可以正常工作。
但是如果JS没有提升和/或不是懒惰,可以想象JS引擎将无法处理相互递归,因为a()
和b()
之间的循环引用实际上意味着其中一个总是被宣布为“为时已晚”。
这就是我在书中所说的全部内容。
答案 2 :(得分:-1)
第二个代码块工作正常,因为在初始化所有函数后调用a(1)
。请尝试以下块:
var a = function(foo){
if (foo > 20) return foo
return b(foo+2)
}
var b = function(foo){
return c(foo) + 1
}
a(1);
var c = function(foo){
return a(foo*2)
}
这会导致错误Uncaught TypeError: c is not a function
,因为function assigned to c
未被提升。这就是你需要吊装的原因。
因为如果您在第一个代码块中声明函数,所有函数都将被挂起,您可以在代码中的任何位置调用a
。在其他情况下则不然。