为什么我可以在函数之前使用它';什么是用JavaScript定义的?

为什么我可以在函数之前使用它';什么是用JavaScript定义的?,javascript,function,Javascript,Function,即使在不同的浏览器中,此代码也始终有效: 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! } fooCh

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

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的演示文稿中,但只提到了这一点。这件事在那里或任何地方都没有解释


有人能告诉我吗?

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


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

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

函数“internalFoo”的主体需要在解析时转到某个地方,因此当JS解释器读取代码(也称为解析)时,将创建函数的数据结构并指定名称


直到代码运行之后,JavaScript才真正尝试找出“internalFoo”是否存在,它是什么,是否可以调用等等。

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

这不同于处理(编译)所有源代码的其他编程上下文,可能会将其与解析引用所需的任何库链接在一起,并构造一个可执行模块,从该模块开始执行

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

当您熟悉JavaScript时,您将非常清楚您需要按照正确的顺序编写内容


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

函数的声明很神奇,它会在执行代码块*中的任何内容之前绑定其标识符

这与使用
函数
表达式的赋值不同,该赋值是按正常的自上而下顺序计算的

如果您将示例更改为:

var internalFoo = function() { return true; };
它会停止工作

函数声明在语法上与函数表达式非常分离,即使它们看起来几乎相同,并且在某些情况下可能不明确

这在章节10.1.3中有记录。不幸的是,即使按照标准,ECMA-262也不是一个非常可读的文档


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

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

if (test condition) {
    var foo;
}

它被称为提升-在定义函数之前调用(调用)函数

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

表达式函数和声明函数

  • 表达式函数:

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

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

    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");
    
  • 声明功能:

    使用以下语法声明的函数不会立即执行。它们被“保存以备将来使用”,并将在稍后调用(调用)时执行。如果在定义where 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);
    }
    

  • 我想它真的不可读。我刚刚读了你指出的10.1.3节,不明白为什么那里的条款会导致这种行为。谢谢您提供的信息。@bobince好吧,当我在这一页上找不到一个关于“提升”的词时,我开始怀疑自己。希望这些评论有足够的谷歌汁™ 这是一个流行的问答组合。考虑对ES5注释规范的链接/摘录进行更新。这篇文章有一些例子:我发现相当多的库在定义函数之前就使用了这个函数,甚至一些语言也正式允许使用它,比如Haskell。老实说,这可能不是一件坏事,因为在某些情况下你可以写得更有表现力。事实上,这是出于完全不同的原因。
    if
    块不创建作用域,而
    function()
    块总是创建一个作用域。真正的原因是全局javascript名称的定义发生在编译阶段,因此即使代码没有运行,名称也会被定义。(很抱歉花了这么长时间才发表评论)在新版本的firefox中,如果代码处于try/catch状态,则此功能不起作用。看这把小提琴:链接不再是死的。链接是死的。这是一个来自archive.org的链接。看来作者认为他们的整个网站都有过时的内容,而不是说这篇博文属于那种类型。
    let fun=theFunction;乐趣();函数theFunction(){}
    也将起作用(节点和浏览器)实际上是“在定义函数之前调用它”?提升已声明名称的作用域,以便为该作用域下的其他代码定义该名称