JavaScript 中的两个同名函数 - 这是如何工作的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5142286/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Two functions with the same name in JavaScript - how can this work?
提问by tillda
As far as I know, function foo() { aaa(); }
is just var foo = function(){ aaa() }
in JavaScript. So adding function foo() { bbb(); }
should either overwrite the foo
variable, or ignore the second definition - that's not the point. The point is that there should be one variable foo
.
据我所知,function foo() { aaa(); }
只是var foo = function(){ aaa() }
在 JavaScript 中。所以添加function foo() { bbb(); }
应该要么覆盖foo
变量,要么忽略第二个定义——这不是重点。关键是应该有一个变量foo
。
So, in this example the me
variable should notbe correctly resolved from inside the methods and it is not in Explorer 8 :-). I came to this example by trying to wrap them into another closure where (var
) me
would be, but I was surprised that it's not necessary:
所以,在这个例子中,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
回答by T.J. Crowder
AFAIK function foo() { aaa(); } is just var foo = function(){ aaa() } in JavaScript.
AFAIK 函数 foo() { aaa(); } 只是 JavaScript 中的 var foo = function(){ aaa() } 。
That's actually incorrect. JavaScript has two different but related things: Function declarations, and function expressions. They happen at different times in the parsing cycle and have different effects.
这其实是不正确的。JavaScript 有两个不同但相关的东西:函数声明和函数表达式。它们发生在解析周期的不同时间并具有不同的效果。
This is a function declaration:
这是一个函数声明:
function foo() {
// ...
}
Function declarations are processed upon entry into the enclosing scope, before any step-by-step code is executed.
在执行任何分步代码之前,函数声明在进入封闭范围时进行处理。
This is a function expression(specifically, an anonymous one):
这是一个函数表达式(特别是匿名的):
var foo = function() {
// ...
};
Function expressions are processed as part of the step-by-step code, at the point where they appear (just like any other expression).
函数表达式作为分步代码的一部分在它们出现的地方进行处理(就像任何其他表达式一样)。
Your quoted code is using a named function expression, which look like this:
您引用的代码正在使用命名函数 expression,如下所示:
var x = function foo() {
// ...
};
(In your case it's within an object literal, so it's on the right-hand side of an :
instead of an =
, but it's still a named function expression.)
(在您的情况下,它在对象文字中,因此它位于 an:
而不是 an的右侧=
,但它仍然是一个命名函数表达式。)
That's perfectly valid, ignoring implementation bugs (more in a moment). It creates a function with the name foo
, doesn'tput foo
in the enclosing scope, and then assigns that function to the x
variable (all of this happening when the expression is encountered in the step-by-step code). When I say it doesn't put foo
in the enclosing scope, I mean exactly that:
这是完全有效的,忽略了实现错误(稍后会更多)。它创建了一个名为 的函数foo
,不放在foo
封闭范围内,然后将该函数分配给x
变量(所有这些都发生在分步代码中遇到表达式时)。当我说它没有放入foo
封闭范围时,我的意思是:
var x = function foo() {
alert(typeof foo); // alerts "function" (in compliant implementations)
};
alert(typeof foo); // alerts "undefined" (in compliant implementations)
Note how that's different from the way function declarationswork (where the function's name isadded to the enclosing scope).
请注意如何将是一个从单向函数的不同声明的工作(如该函数的名称被添加到封闭范围)。
Named function expressions work on compliant implementations. Historically, there were bugs in implementations (early Safari, IE8 and earlier). Modern implementations get them right, including IE9 and up. (More here: Double takeand here: Named function expressions demystified.)
命名函数表达式适用于兼容的实现。从历史上看,实现中存在错误(早期的 Safari、IE8 和更早版本)。现代实现使它们正确,包括 IE9 及更高版本。(更多信息:Double take和这里:命名函数表达式揭秘。)
So, in this example the
me
variable shoudl not be corectly resolved from inside the methods
因此,在此示例中,
me
变量不应从方法内部正确解析
Actually, it should be. A function's true name (the symbol between function
and the opening parenthesis) is always in-scope within the function (whether the function is from a declaration or a named function expression).
其实应该是的。函数的真实名称(function
左括号和左括号之间的符号)始终在函数范围内(无论函数来自声明还是命名函数表达式)。
NOTE: The below was written in 2011. With the advances in JavaScript since, I no longer feel the need to do things like the below unless I know I'm going to be dealing with IE8 (which is very rare these days).
注意:下面是 2011 年写的。随着 JavaScript 的进步,我不再觉得需要做下面的事情,除非我知道我将要处理 IE8(这在这些日子里非常罕见)。
Because of implementation bugs, I used to avoid named function expressions. You can do that in your example by just removing the me
names, but I prefer named functions, and so for what it's worth, here's how I used to write your object:
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;
})();
(Except I'd probably use a shorter name than publicSymbols
.)
Here's how that gets processed:
- An anonymous enclosing function is created when the
var foo = ...
line is encountered in the step-by-step code, and then it is called (because I have the()
at the very end). - Upon entry into the execution context created by that anonymous function, the
bar1_me
andbar2_me
function declarations are processed and those symbols are added to the scope inside that anonymous function (technically, to the variable objectfor the execution context). - The
publicSymbols
symbol is added to the scope inside the anonymous function. (More: Poor misunderstoodvar
) - Step-by-step code begins by assigning
{}
topublicSymbols
. - Step-by-step code continues with
publicSymbols.bar1 = bar1_me;
andpublicSymbols.bar2 = bar2_me;
, and finallyreturn publicSymbols;
- The anonymous function's result is assigned to
foo
.
These days, though, unless I'm writing code I know needs to support IE8 (sadly, as I write this in November 2015 it still has significant global market share, but happily that share is plummetting), I don't worry about it. All modern JavaScript engines understand them just fine.
You can also write that like this:
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);
}
})();
...since those are function declarations, and thus are hoisted. I don't usually do it like that, as I find it easier to do maintenance on large structures if I do the declaration and the assignment to the property next to each other (or, if not writing for IE8, on the same line).
由于实现错误,我曾经避免使用命名函数表达式。您可以在您的示例中通过删除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;
})();
(除了我可能会使用比 更短的名称publicSymbols
。)
以下是处理方式:
- 当在
var foo = ...
分步代码中遇到该行时,会创建一个匿名封闭函数,然后调用它(因为我()
在最后有 )。 - 在进入由该匿名函数创建的执行上下文时,将处理
bar1_me
和bar2_me
函数声明,并将这些符号添加到该匿名函数内的作用域(技术上,添加到执行上下文的变量对象)。 - 该
publicSymbols
符号被添加到匿名函数内的作用域中。(更多:可怜的误解var
) - 分步代码从分配
{}
给开始publicSymbols
。 - 分步代码以
publicSymbols.bar1 = bar1_me;
和继续publicSymbols.bar2 = bar2_me;
,最后return publicSymbols;
- 匿名函数的结果分配给
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);
}
})();
...因为这些是函数声明,因此被提升。我通常不会这样做,因为我发现如果我将声明和分配给彼此相邻的属性(或者,如果不是为 IE8 编写,则在同一行上),对大型结构进行维护会更容易.
回答by jAndy
Both me
lookups, are only visible/available insidethe function expression.
这两种me
查找,才可见/可用的内部函数表达式。
Infact those two are named function expressions, and the ECMAscript specification tells us, that the name of an expression is not exposed to the such called Variable object
.
事实上,这两个是命名函数表达式,ECMAscript 规范告诉我们,表达式的名称不会暴露给这样的被调用的Variable object
.
Well I tried to put that only in a few words, but while trying to find the right words, this ends up in pretty deep chain of ECMAscript behavior. So, function expression
are notstored in a Variable
/ Activation Object
. (Would lead to the question, who those guys are...).
好吧,我试图只用几句话来表达,但是在尝试找到正确的词时,这最终导致了非常深的 ECMAscript 行为链。所以,function expression
在没有存储在Variable
/ Activation Object
。(会引出一个问题,这些人是谁......)。
Short: Every time a function is called, a new Context
is created. There is some "blackmagic" kind of guy that is called, Activation object
which stores some stuff. For instance, the
简而言之:每次调用函数时,Context
都会创建一个新函数。有一种叫做“blackmagic”的家伙,Activation object
可以存储一些东西。例如,
- arguments of the function
- the [[Scope]]
- any variables created by
var
- 函数的参数
- 范围]]
- 由创建的任何变量
var
For instance:
例如:
function foo(test, bar) {
var hello = "world";
function visible() {
}
(function ghost() {
}());
}
The Activation Object for foo
would look like:
的激活对象foo
看起来像:
- arguments: test, bar
- variables: hello (string), visible (function)
- [[Scope]]: (possible parent function-context), Global Object
- 参数:测试,酒吧
- 变量:你好(字符串),可见(函数)
- [[Scope]]:(可能的父函数上下文),全局对象
ghost
is not stored in the AO! it would just be accesssible under that name withinthe function itself. While visible()
is a function declaration(or function statement) it is stored in the AO. This is because, a function declarationis evaluated when parsingand function expressionis evaluated at runtime.
ghost
没有存储在 AO 中!它只是可以在函数本身中以该名称访问。虽然visible()
是函数声明(或函数语句),但它存储在 AO 中。这是因为,在解析和函数表达式在运行时求值时会求值函数声明。
回答by Aaron Digulla
What happens here is that function()
has many different meanings and uses.
这里发生的是它function()
有许多不同的含义和用途。
When I say
当我说
bar1 : function me() {
}
then that's 100% equivalent to
那么这 100% 相当于
bar1 : function() {
}
i.e. the name doesn't matter when you use function to assign the variable bar1
. Inside, me
is assigned but as soon as the function definition is left (when you assign bar2
), me
is created again as a local variable for the function definition that is stored in bar2
.
即当您使用函数分配变量时名称无关紧要bar1
。在内部,me
被赋值,但一旦函数定义被留下(当你赋值时bar2
),它me
就会被再次创建为存储在 中的函数定义的局部变量bar2
。