2011-02-28 113 views
14

据我所知,function foo() { aaa(); }只是在JavaScript中的var foo = function(){ aaa() }。因此,添加function foo() { bbb(); }应覆盖foo变量,或忽略第二个定义 - 这不是重点。重点是应该有一个变量fooJavaScript中具有相同名称的两个函数 - 该如何工作?

所以,在这个例子中me变量应该被正确地从方法内解决,它不是在浏览器8 :-)。我来到了这个例子,试图将它们包装成另一封在那里(varme会是这样,但我很惊讶,这是没有必要:

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/

+8

我读过你的问题3次,我仍然无法理解你的问题 – Luis

+0

@Luis:这是创建和范围是什么,他们有函数名何时以及如何对一个玄之又玄的问题。是的,追踪有点棘手。 :-) –

+0

对不起,如果问题出在我的英语,我不是一个母语。 – tillda

回答

32

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

这实际上是不正确的。 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

所以,在这个例子中me变量shoudl不corectly从方法

其实里面解决的,也是应该的。函数的真实名称(function与左括号之间的符号)始终在函数内(无论函数来自声明还是命名函数表达式)。

注意:下面是在2011年写的。随着JavaScript的进步,我不再需要做下面的事情,除非我知道我将要处理IE8(这是非常这些天罕见)。

由于执行错误的,我用来避免命名的函数表达式。你可以做你的榜样仅通过去除me名称,但I prefer named functions,因此对于它的价值,这里就是我以前写你的对象:

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

下面是该得到处理:

  1. 当在一步一步的代码中遇到var foo = ...行会创建一个匿名的封闭功能,然后它被称为(因为我有Ť他在最后)()
  2. 一旦进入由匿名函数创建的执行上下文,则bar1_mebar2_me函数声明被处理并且这些符号被添加到匿名函数内的范围(在技术上,与可变对象用于执行上下文)。
  3. publicSymbols符号被添加到匿名函数的范围内。 (更多:Poor misunderstood var
  4. 分步代码首先将{}指定为publicSymbols
  5. 步骤一步码连续用publicSymbols.bar1 = bar1_me;publicSymbols.bar2 = bar2_me;,最后return publicSymbols;
  6. 匿名函数的结果被分配给foo

这些天来,虽然,除非我在写代码,我知道需要支持IE8(可悲的是,我写这篇文章在2015年11月它还是有significant global market share,但令人高兴的是份额plummetting),我不知道担心它。所有现代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编写的话,在同一行中),则更容易对大型结构进行维护。 。

+0

+1以获得详细的答案。在IE/JScript中,命名函数表达式被错误地处理是一个已知的问题。当他们编写基于ECMAScript 5th Edition的全新JavaScript引擎时,他们在IE9中解决了这个问题。 –

3

两个me查找,才可见/可用内部的函数表达式。

逸岸这两个是命名的函数表达式和ECMAScript规范告诉我们,一个表达式的名称不暴露在这种被称为Variable object


嗯,我试图把只有几句话,但在试图找到合适的话,这在ECMAScript的行为相当深链结束。因此,function expression而不是存储在Variable/Activation Object。 (会导致这个问题,这些人是谁......)。

简称:每次调用某个函数时,都会创建一个新的Context。有一些叫做“blackmagic”的家伙叫做Activation object,它存储了一些东西。例如,该函数的

  • 参数
  • 的[[范围]]
  • 通过var

创建例如任何变量:

function foo(test, bar) { 
    var hello = "world"; 

    function visible() { 
    } 

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

激活对象对于foo看起来像:

  • 参数:测试,酒吧
  • 变量:你好(字符串),可见(功能)
  • [[范围]]:(可能的父功能上下文),全局对象

ghost不存储在AO中!它只能以这个名称在之内的函数本身进行访问。而visible()函数声明(或函数声明)它存储在AO中。这是因为,当解析函数表达式在运行时计算一个函数声明进行评价。

1

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

当我说

bar1 : function me() { 
} 

那么这相当于100%

bar1 : function() { 
} 

即当您使用功能来分配变量bar1的名称并不重要。在内部,me分配,但只要函数定义是左(当你将bar2),再次创建为存储在bar2函数定义一个局部变量me

+0

*“......那么这相当于100%......” *这不是** 100 **%相同(前者的例子给出的函数名*和分配名为功能'bar1',后者为'bar1'分配一个* anonymous *函数),但它应该几乎相同,是的。不幸的是,重要的是,具有最大安装基数的JavaScript解释器(IE中的JScript <= 8)第一个完全错误。 :-) –

相关问题