为什么在Javascript中定义函数之前可以使用它?

此代码始终可以在各个浏览器中运行:

function fooCheck() { alert(internalFoo()); return internalFoo(); function internalFoo() { return true; } } fooCheck(); 

虽然我找不到一个为什么它应该工作的单一的参考。 我在John Resig的演讲笔记中首先看到了这一点,但只是提到了这一点。 对于这个问题,没有任何解释。

有人请赐教吗?

function声明是神奇的,并且使其标识符在其代码块*中的任何内容被执行之前被绑定。 这不同于以正常自上而下的顺序评估的functionexpression式的赋值,所以如果您将示例更改为:

 var internalFoo = function() { return true; }; 

它会停止工作。 函数声明在语法上与函数expression式完全分离,即使它们看起来几乎相同,并且在某些情况下可能不明确。

这在ECMAScript标准10.1.3节中有logging。 不幸的是,ECMA-262即使是标准的标准也不是一个非常易读的文件!

*:包含function,块,模块或脚本。

浏览器从头到尾读取您的html,并且可以在读取并分析为可执行块(variables声明,函数定义等)时执行它。但是在任何时候,只能使用html之前定义的内容。

这与处理(编译)所有源代码的其他编程上下文不同,将它与所需的任何库链接在一起,并构build一个可执行模块,此时执行开始。

您可以定义引用项目(variables,其他函数等等)的函数,这些函数是在进一步定义的基础上进行的,但是只有所有函数都可用时,才能执行这些函数。

随着您熟悉JavaScript,您将会深刻地意识到您需要按照正确的顺序编写代码。

修订:要确认接受的答案(上面),请使用Firebug来浏览网页的脚本部分。 你会看到它从函数跳到函数,在实际执行任何代码之前只访问第一行。

它被称为HOISTING – 在被定义之前调用(调用)一个函数。

我想要写的两种不同types的函数是:

expression式函数和减速函数

1-expression式函数:函数expression式可以存储在一个variables中,所以它们不需要函数名。它们也将被命名为匿名函数(一个没有名字的函数)。 要调用(调用)它们总是需要使用variables名称 。如果调用之前的调用(这意味着在此处没有提升),则这些types的函数将不起作用。 我们总是必须先定义expression式函数然后调用它。

 let lastName = function (family) { console.log("My last name is " + family); }; let x = lastName("Lopez"); 

这是你可以写在ES6中的方法:

lastName =(family)=> console.log(“我的姓氏是”+ family);

x = lastName(“Lopez”);

2-减速函数:使用以下语法声明函数不会立即执行。 它们被“保存以供以后使用”,并且当它们被调用(被调用)时将在稍后被执行。如果在它们被定义之前或之后调用它们,则这些types的function起作用。 如果在定义之前调用减速function – 起升 – 正常工作。

 function Name(name) { console.log("My cat's name is " + name); } Name("Chloe"); 

举例:

 Name("Chloe"); function Name(name) { console.log("My cat's name is " + name); } 

我只使用JavaScript一点。 我不确定这是否会有所帮助,但看起来与您正在谈论的内容非常相似,可能会提供一些见解:

http://www.dustindiaz.com/javascript-function-declaration-ambiguity/

有些语言要求在使用之前必须定义标识符。 原因是编译器在源代码上使用了单个传递。

但是,如果有多个通行证(或一些支票被推迟),你可以完全没有这个要求生活。 在这种情况下,代码可能首先被读取(并解释),然后链接被设置。

函数“internalFoo”的主体需要在parsing时到达某处,所以当JS解释器读取代码(又称parsing)时,会创build该函数的数据结构并分配名称。

之后才运行代码,JavaScript实际上试图找出“internalFoo”是否存在,它是什么以及是否可以调用等等。

出于同样的原因,以下将始终将foo放在全局名称空间中:

 if (test condition) { var foo; }