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

IT技术 javascript function
2021-02-05 19:33:57

即使在不同的浏览器中,此代码也始终有效:

function fooCheck() {
  alert(internalFoo()); // We are using internalFoo() here...

  return internalFoo(); // And here, even though it has not been defined...

  function internalFoo() { return true; } //...until here!
}

fooCheck();

不过,我找不到一个关于它为什么应该工作的参考。我第一次看到这个是在 John Resig 的演讲笔记中,但只是提到了。那里或任何地方都没有关于此事的解释。

有人可以启发我吗?

6个回答

function声明是魔术并导致其标识符在其代码块*被执行之前的任何约束。

这与带有function表达式的赋值不同,后者以正常的自上而下的顺序进行计算。

如果您将示例更改为:

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

它会停止工作。

函数声明在语法上与函数表达式完全不同,尽管它们看起来几乎相同并且在某些情况下可能会产生歧义。

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

*:包含函数、块、module或脚本。

我发现很多库在定义之前使用该函数,甚至某些语言官方允许它,例如。haskell。老实说,这可能不是一件坏事,因为在某些情况下您可以写得更有表现力。
2021-03-20 19:33:57
这是一个流行的问答组合。考虑使用 ES5 注释规范的链接/摘录进行更新。(哪个更容易访问。)
2021-03-24 19:33:57
我想它真的不可读。我刚刚阅读了您指向 10.1.3 的部分,但不明白为什么那里的规定会导致这种行为。谢谢你的信息。
2021-03-25 19:33:57
这篇文章有一些例子:JavaScript-Scopeing-and-Hoisting
2021-04-06 19:33:57
@bobince 好的,当我在此页面上找不到任何提及“提升”一词的内容时,我开始怀疑自己。希望这些评论有足够的 Google Juice™ 来解决问题:)
2021-04-08 19:33:57

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

我想写的两种不同类型的函数是:

表达式函数和声明函数

  1. 表达式函数:

    函数表达式可以存储在变量中,因此它们不需要函数名称。它们也将被命名为匿名函数(一个没有名字的函数)。

    要调用(调用)这些函数,它们总是需要一个变量名如果在定义之前调用这种函数将不起作用,这意味着这里不会发生提升。我们必须始终先定义表达式函数,然后再调用它。

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

    这是你在 ECMAScript 6 中编写它的方式:

    lastName = (family) => console.log("My last name is " + family);
    
    x = lastName("Lopez");
    
  2. 声明函数:

    使用以下语法声明的函数不会立即执行。它们被“保存以备后用”,并且将在稍后被调用(调用)时执行。如果您在定义了 is 的位置之前或之后调用它,则这种类型的函数有效。如果在定义之前调用声明函数,提升工作正常。

    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);
    }
    
let fun = theFunction; fun(); function theFunction() {} 也可以工作(节点和浏览器)
2021-03-23 19:33:57
提升实际上是“在定义之前调用函数”吗?提升已声明名称的范围,以便为该范围内的其他代码定义它——这大致是 JavaScript 所做的,允许您在声明之前调用该函数,这就是提升。
2021-03-25 19:33:57

浏览器从头到尾读取您的 HTML,并可以在它被读取并解析为可执行块(变量声明、函数定义等)时执行它。但在任何时候都只能使用在那之前脚本中定义的内容。

这与处理(编译)所有源代码的其他编程上下文不同,可能将它与解析引用所需的任何库链接在一起,并构建一个可执行module,然后执行开始。

您的代码可以引用进一步定义的命名对象(变量、其他函数等),但在所有部分都可用之前,您无法执行引用代码。

随着您对 JavaScript 的熟悉,您将非常清楚您需要以正确的顺序编写内容。

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

某些语言要求在使用前必须定义标识符。这样做的一个原因是编译器对源代码使用单次传递。

但是,如果有多次通过(或某些检查被推迟),您可以在没有该要求的情况下完美生活。在这种情况下,可能首先读取(并解释)代码,然后设置链接。

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

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

这是来自 archive.org快照看起来作者因为内容过时而关闭了他们的整个网站,而不是这篇博文属于该类别。
2021-03-15 19:33:57
链接不再死了。
2021-04-02 19:33:57
链接已死。
2021-04-09 19:33:57