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

标签 javascript function closures strict-mode

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

因此,在此示例中,应该从方法内部正确解析变量而不是,并且它不在Explorer 8 :-) 中。我通过尝试将它们包装到另一个将闭合(me)var的闭包中来进入此示例,但令我感到惊讶的是,它不是必需的:

    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具有两个不同但相关的内容:函数声明和函数表达式。它们在解析周期的不同时间发生,并产生不同的效果。

这是一个函数声明:
function foo() {
    // ...
}

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

这是一个函数表达式(具体地说,是一个匿名表达式):
var foo = function() {
    // ...
};

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

您引用的代码使用命名函数表达式,如下所示:
var x = function foo() {
    // ...
};

(在您的情况下,它位于对象文字中,因此它位于:的右侧,而不是=,但它仍是命名函数表达式。)

这是完全正确的,忽略了实现错误(稍后会介绍)。它创建一个名称为foo的函数,不将foo放在封闭范围内,然后将该函数分配给x变量(所有这些都在分步代码中遇到表达式时发生)。当我说它没有将foo放在封闭范围内时,我的意思是:
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和此处:Named function expressions demystified。)

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



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

注意:以下内容写于2011年。自JavaScript的进步以来,我不再感到需要执行以下内容,除非我知道我将要处理IE8(这在今天已经非常罕见了) 。

由于实现错误,我曾经避免使用命名函数表达式。您可以在示例中做到这一点,只需删除me名称,但删除I prefer named functions,就其值(value)而言,这就是我以前编写对象的方式:
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符号被添加到匿名函数内部的作用域中。 (更多:Poor misunderstood var )
  • 分步代码首先将{}分配给publicSymbols
  • 分步代码以publicSymbols.bar1 = bar1_me;publicSymbols.bar2 = bar2_me;继续,最后是return publicSymbols;
  • 匿名函数的结果分配给foo

  • 但是,这些天来,除非我正在编写代码,否则我知道需要支持IE8(可悲的是,当我在2015年11月编写此代码时,它仍然具有significant global market share,但是很高兴份额急剧下降),我不必为此担心。所有现代的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);
        }
    })();
    

    ...由于这些是函数声明,因此已被吊起。我通常不会那样做,因为如果我将声明和对属性的分配彼此相邻(或者如果不为IE8编写,则在同一行),我发现对大型结构进行维护会更容易。

    关于javascript - JavaScript中两个具有相同名称的函数-如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5142286/

    相关文章:

    javascript - 无法在 jQuery 中调用按钮作为事件处理程序

    postgresql - 如何传递 ENUM 变量作为 POSTGRESQL 函数的输入

    javascript - 3/6 标签 html 布局,其中标签占据整个宽度

    javascript - 根据 URL 参数过滤 'ng-repeat'

    c - 对具有可变数量参数的函数中的复数求和

    functional-programming - 关于闭包中词法绑定(bind)的更多解释?

    php - PHP 中的参数闭包? (柯里化(Currying))

    Golang 延迟关闭

    c# - 使用dropzone需要添加额外的值

    swift - 函数调用明确还是 Xcode 8 错误?