JavaScript中具有相同名称的两个函数 - 这如何工作?

til*_*lda 17 javascript closures function strict-mode

据我所知,function foo() { aaa(); }只是var foo = function(){ aaa() }在JavaScript中.所以添加function foo() { bbb(); }应该覆盖foo变量,或忽略第二个定义 - 这不是重点.关键是应该有一个变量foo.

所以,在这个例子中,me变量应该没有被正确地从里面的方法解决,这是不是在资源管理器8 :-).我通过尝试将它们包装到另一个闭包中来实现这个例子,其中(var)me将是,但我很惊讶它没有必要:

    var foo = {
        bar1 : function me() {
            var index = 1;
            alert(me);
        },
        bar2 : function me() {
            var index = 2;
            alert(me);
        }    
    };

    foo.bar1(); // Shows the first one
    foo.bar2(); // Shows the second one
Run Code Online (Sandbox Code Playgroud)

演示:http://jsfiddle.net/W5dqy/5/

T.J*_*der 33

AFAIK函数foo(){aaa(); 在JavaScript中只是var foo = function(){aaa()}.

这实际上是错误的.JavaScript有两个不同但相关的东西:函数声明和函数表达式.它们在解析周期中的不同时间发生并具有不同的效果.

这是一个函数声明:

function foo() {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

在执行任何分步代码之前,在进入封闭范围时处理函数声明.

这是一个函数表达式(具体来说,是一个匿名函数):

var foo = function() {
    // ...
};
Run Code Online (Sandbox Code Playgroud)

函数表达式作为逐步代码的一部分进行处理,在它们出现的位置处(就像任何其他表达式一样).

您引用的代码使用的是命名函数表达式,如下所示:

var x = function foo() {
    // ...
};
Run Code Online (Sandbox Code Playgroud)

(在你的情况下,它在一个对象文字中,所以它位于一个:而不是一个的右侧=,但它仍然是一个命名的函数表达式.)

这是完全有效的,忽略了实现错误(稍后更多).它创建一个具有名称的函数foo,放入foo封闭范围,然后将该函数分配给x变量(当在逐步代码中遇到表达式时,所有这些都发生).当我说它没有放入foo封闭范围时,我的意思是:

var x = function foo() {
    alert(typeof foo); // alerts "function" (in compliant implementations)
};
alert(typeof foo);     // alerts "undefined" (in compliant implementations)
Run Code Online (Sandbox Code Playgroud)

请注意这与函数声明的工作方式有何不同(函数名称添加到封闭范围中).

命名函数表达式适用于兼容的实现.从历史上看,实现中存在错误(早期的Safari,IE8和更早版本).现代实现使它们正确,包括IE9及更高版本.(更多信息:Double take and here:命名函数表达式揭秘.)

因此,在此示例中,me变量shoudl不能从方法内部进行核心解析

实际上,它应该是.函数的真实名称(function开头括号之间的符号)始终在函数内(函数来自声明或命名函数表达式).

注意:下面是在2011年写的.随着JavaScript的进步,我不再觉得有必要做以下的事情,除非我知道我将要处理IE8(这些日子非常罕见).

由于实现错误,我曾经避免使用命名函数表达式.您可以通过删除me名称在您的示例中执行此操作,但我更喜欢命名函数,因此对于它的值,这是我以前编写对象的方式:

var foo = (function(){
    var publicSymbols = {};

    publicSymbols.bar1 = bar1_me;
    function bar1_me() {
        var index = 1;
        alert(bar1_me);
    }

    publicSymbols.bar2 = bar2_me;
    function bar2_me() {
        var index = 2;
        alert(bar2_me);
    }

    return publicSymbols;
})();
Run Code Online (Sandbox Code Playgroud)

(除了我可能使用比...更短的名字publicSymbols.)

以下是处理方式:

  1. 当在var foo = ...逐步代码中遇到该行时,将创建一个匿名封闭函数,然后调用它(因为我()在最后).
  2. 在进入由该匿名函数创建的执行上下文时,处理bar1_mebar2_me函数声明,并将这些符号添加到该匿名函数内的范围内(从技术上讲,添加到执行上下文的变量对象).
  3. publicSymbols符号将添加到匿名函数内的范围中.(更多:可怜的误会var)
  4. 分步代码从分配{}到开始publicSymbols.
  5. 逐步的代码继续publicSymbols.bar1 = bar1_me;publicSymbols.bar2 = bar2_me;,最后return publicSymbols;
  6. 匿名函数的结果已分配给foo.

但是,现在,除非我正在编写代码,否则我需要支持IE8(遗憾的是,我在2015年11月写这篇文章时,它仍然拥有重要的全球市场份额,但很高兴这一份额直线下降),我不担心它.所有现代JavaScript引擎都很了解它们.

你也可以这样写:

var foo = (function(){
    return {
        bar1: bar1_me,
        bar2: bar2_me
    };

    function bar1_me() {
        var index = 1;
        alert(bar1_me);
    }

    function bar2_me() {
        var index = 2;
        alert(bar2_me);
    }
})();
Run Code Online (Sandbox Code Playgroud)

......因为那些是功能声明,因此被悬挂.我通常不这样做,因为我发现如果我做声明并且相互旁边的属性分配(或者,如果不是为IE8编写,则在同一行上),对大型结构进行维护更容易.

  • +1获得详细答案。一个已知的问题是命名函数表达式在IE / JScript中处理不正确。他们在编写基于ECMAScript 5th Edition的全新JavaScript引擎时,在IE9中解决了该问题。 (2认同)