function Identifier ( FormalParameterList opt ){ FunctionBody }
FunctionExpression :
function Identifier opt ( FormalParameterList opt ){ FunctionBody }
We can see that when identifier is omitted, that something can only be an expression. But what if identifier is present? How can one tell whether it is a function declaration or a function expression - they look identical after all? It appears that ECMAScript differentiates between two based on a context. If a is part of, say, assignment expression, it is considered a function expression. If, on the other hand, is contained in a function body or in a (top level of) program itself - it is parsed as a function declaration.
我们可以看到,当标示符被省略的时候,这样的结构只能是一个函数表达式。但是当标示符出现的时候情况是怎样的呢。他究竟是一个函数声明还是一个函数表达式呢,他们看上去是完全一样的。但是ECMAScript是通过上下文来区分两者的。如果function foo(){}是一个赋值表达式的一部分,他就被认为是函数表达式。相反,如果function foo(){}包含在一个函数体中,或者在程序的最上层的代码中,他就被解释成为一个函数声明。
function foo(){}; // 声明,因为作为最上层程序的一部分declaration, since it's part of a Program
var bar = function foo(){}; // 表达式,因为是复制表达式的一部分expression, since it's part of an AssignmentExpression
new function bar(){}; // 表达式,因为他是New表达式的一部分。expression, since it's part of a NewExpression
(function(){
function bar(){}; // 声明,因为是函数图的一部分declaration, since it's part of a FunctionBody
})();
There’s a subtle difference in behavior of declarations and expressions.
声明和表达式在作用上有这细微的差别。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)First of all, function declarations are parsed and evaluated before any other expressions are. Even if declaration is positioned last in a source, it will be evaluated foremost any other expressions contained in a scope. The following example demonstrates how function is already defined by the time is executed, even though it’s being declared right after it:
首先,函数声明是在所有表达式之前被解析和求值。即使声明被放在代码的最后,他也会在包含它的作用域内的所有表达式之前被求值。下面的例子将说明即使fn函数在alert执行之后才被声明,但是在alert被执行的时候fn函数已经被定义了。
alert(fn());
function fn() {
return 'Hello world!';
}
Another important trait of function declarations is that declaring them conditionally is non-standardized and varies across different environments. You should never rely on functions being declared conditionally and use function expressions instead.
函数声明的另外一个重要的特点是,在条件语句中声明他们的情况在ECMA标准中是没有说明的,并且在不同的环境中(也就是不同的浏览器)中是不同的。因此你不能依赖函数的条件声明,而是应该使用函数表达式来代替。
// 千万不要这样做Never do this!
// 有些浏览器会声返回first的foo函数Some browsers will declare `foo` as the one returning 'first',
// 有些浏览器则会声明返回second的foo函数while others - returning 'second'
if (true) {
function foo() {
return 'first';
}
}
else {
function foo() {
return 'second';
}
}
foo();
//作为替代你可以使用函数表达式 Instead, use function expressions:
var foo;
if (true) {
foo = function() {
return 'first';
}
}
else {
foo = function() {
return 'second';
}
}
foo();
Function expressions can actually be seen quite often. A common pattern in web development is to fork function definitions based on some kind of a feature test, allowing for the best performance. Since such forking usually happens in the same scope, it is almost always necessary to use function expressions. After all, as we know by now, function declarations should not be executed conditionally:
函数表达式可能更常见一些。在web开发中的一个普通的模式就是根据一些某种功能测试的情况来fork函数定义,允许达到最好的性能。既然这个fork通常发生在同一个作用域内,所以他需要使用函数表达式。毕竟,如我们所知,函数定义不应该被条件执行
var contans = (function() {有名函数表达式
var docEl = document.documentElement;
if (typeof docEl.compareDocumentPosition != 'undefined') {
return function(el, b) {
return (el.compareDocumentPosition(b) & 16) !== 0;
}
}
else if (typeof docEl.contains != 'undefined') {
return function(el, b) {
return el !== b && el.contains(b);
}
}
return function(el, b) {
if (el === b) return false;
while (el != b && (b = b.parentNode) != null);
return el === b;
}
})();
Quite obviously, when a function expression has a name (technically - Identifier), it is called a named function expression. What you’ve seen in the very first example - - was exactly that - a named function expression with being a function name. An important detail to remember is that this name is only available in the scope of a newly-defined function; specs mandate that an identifier should not be available to an enclosing scope:
非常显然那,当一个函数表达式含有函数名(从技术上讲就是一个标示符),他就被称作有名函数表达式。在你看到的第一个例子中 var bar=function foo(){}就是这样,他是一个以foo作为函数名的有名函数表达式。最重要的一个细节就是这个函数名只有在新定义的函数的作用域内才可访问,ECMA要求一个标示符不应该被一个封闭的作用域所访问。
var f = function foo(){
return typeof foo; // foo在内部作用域可以被访问 "foo" is available in this inner scope
};
//‘foo’在外部不可见 `foo` is never visible "outside"
typeof foo; // "undefined"
f(); // "function"
So what’s so special about these named function expressions? Why would we want to give them names at all?
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)It appears that named functions make for a much more pleasant debugging experience. When debugging an application, having a call stack with descriptive items makes a huge difference.
因此,为什么这些有名函数表达式如此特别?为什么我们想要给他们名字呢。
可以看到有命名的函数在调试过程中可能更加方便一些。当调试一个应用程序的时候拥有一个含有描述项的调用栈会有很大的不同
猜你喜欢