关于两个在javascript中同名的函数:两个在javascript中同名的函数-这是如何工作的?

Two functions with the same name in JavaScript - how can this work?

据我所知,function foo() { aaa(); }在javascript中只是var foo = function(){ aaa() }。因此,添加function foo() { bbb(); }应该覆盖foo变量,或者忽略第二个定义——这不是重点。重点是应该有一个变量foo

因此,在本例中,不应该从方法内部正确地解析me变量,而且它不在资源管理器8中:-)。我在这个例子中试图将它们包装成另一个闭包,其中(varme会是,但我惊讶地发现这是不必要的:

1
2
3
4
5
6
7
8
9
10
11
12
13
    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

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


AFAIK function foo() { aaa(); } is just var foo = function(){ aaa() } in JavaScript.

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

这是一个函数声明:

1
2
3
function foo() {
    // ...
}

函数声明在进入封闭范围时进行处理,然后再执行任何分步代码。

这是一个函数表达式(特别是匿名表达式):

1
2
3
var foo = function() {
    // ...
};

函数表达式被作为逐步代码的一部分处理,在它们出现的地方(就像任何其他表达式一样)。

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

1
2
3
var x = function foo() {
    // ...
};

(在您的例子中,它在对象文本中,所以它位于:的右侧,而不是=的右侧,但它仍然是一个命名函数表达式。)

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

1
2
3
4
var x = function foo() {
    alert(typeof foo); // alerts"function" (in compliant implementations)
};
alert(typeof foo);     // alerts"undefined" (in compliant implementations)

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

命名函数表达式用于兼容的实现。历史上,在实现中存在错误(早期的Safari、IE8和早期版本)。现代实现使它们正确,包括IE9和更高版本。(这里的更多内容:double take和here:已命名的函数表达式已解除定义。)

So, in this example the me variable shoudl not be corectly resolved from inside the methods

事实上,应该是。函数的真名称(function和左括号之间的符号)始终在函数范围内(无论函数是来自声明还是命名函数表达式)。

注:以下为2011年编写。随着Javascript的发展,我不再觉得有必要做下面这样的事情,除非我知道我将要处理IE8(这在现在是非常罕见的)。

由于实现错误,我常常避免使用命名函数表达式。在您的示例中,您只需删除me名称就可以做到这一点,但我更喜欢命名函数,因此,就其价值而言,下面是我如何编写您的对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
})();

(除了我可能会用一个比publicSymbols短的名字。)

这是如何处理的:

  • 当在分步代码中遇到var foo = ...行时,会创建一个匿名封闭函数,然后调用它(因为我最后有())。
  • 当进入由该匿名函数创建的执行上下文时,将处理bar1_mebar2_me函数声明,并将这些符号添加到该匿名函数内的作用域中(从技术上讲,添加到执行上下文的变量对象中)。
  • publicSymbols符号添加到匿名函数内的作用域中。(更多:误会不深11〔14〕)
  • 一步一步的代码从分配{}publicSymbols开始。
  • 循序渐进的代码继续与publicSymbols.bar1 = bar1_me;publicSymbols.bar2 = bar2_me;进行,最后是return publicSymbols;
  • 匿名函数的结果分配给foo
  • 不过,现在,除非我正在编写代码,否则我知道需要支持IE8(遗憾的是,正如我在2015年11月写的那样,它仍然拥有巨大的全球市场份额,但令人高兴的是,它的份额正在下降),我不担心它。所有现代的javascript引擎都能很好地理解它们。

    你也可以这样写:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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);
        }
    })();

    …因为它们是函数声明,因此被提升。我通常不会这样做,因为我发现,如果我对彼此相邻的财产进行申报和转让(或者,如果不是为IE8写,在同一行),就更容易对大型结构进行维护。


    两个me查找仅在函数表达式中可见/可用。

    事实上,这两个表达式都是命名函数表达式,而ecmascript规范告诉我们,表达式的名称不会暴露于所谓的Variable object中。

    好吧,我试着只用几句话来表达,但是当我试图找到合适的词语时,这最终导致了一系列令人欣喜若狂的行为。因此,function expression不存储在VariableActivation Object中。(会引出问题,那些人是谁…)。

    短:每次调用函数时,都会创建一个新的Context。有一种叫"黑魔法"的家伙,叫Activation Object,它可以储存一些东西。例如,

    • 函数的参数
    • [ [范围] ]
    • var创建的任何变量

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function foo(test, bar) {
        var hello ="world";

        function visible() {
        }

        (function ghost() {
        }());
    }

    foo的激活对象如下:

    • 参数:测试,bar
    • 变量:hello(字符串),visible(函数)
    • [[scope]]:(可能的父函数上下文),全局对象

    ghost不存储在AO中!它在函数本身的名称下是可以访问的。虽然visible()是一个函数声明(或函数语句),但它存储在AO中。这是因为,在解析时计算函数声明,在运行时计算函数表达式。


    这里所发生的是,function()有许多不同的含义和用途。

    当我说

    1
    2
    bar1 : function me() {
    }

    那么100%相当于

    1
    2
    bar1 : function() {
    }

    也就是说,当使用函数分配变量bar1时,名称并不重要。在内部,会分配me,但只要函数定义保留(分配bar2时),就会再次创建me作为存储在bar2中的函数定义的局部变量。