1.声明函数和函数表达式
function foo(){} // 声明,因为它是程序的一部分
var bar = function foo(){}; // 表达式,因为它是赋值表达式的一部分
new function bar(){}; // 表达式,因为它是new表达式
(function(){
function bar(){} // 声明,因为它是函数体的一部分
})();
--------------------------------------------------
function foo(){} // 函数声明
(function foo(){}); // 函数表达式:包含在分组操作符内
try {
(var x = 5); // 分组操作符,只能包含表达式而不能包含语句:这里的var就是语句
} catch(err) {// SyntaxError
}
-----------------
try {
{
"x": 5
}; // "{" 和 "}" 做解析成代码块
} catch (err) {
// SyntaxError
}
({
"x": 5
}); // 分组操作符强制将"{" 和 "}"作为对象字面量来解析、
表达式和声明存在着十分微妙的差别,首先,函数声明会在任何表达式被解析和求值之前先被解析和求值,即使你的声明在代码的最后一行,它也会在同作用域内第一个表达式之前被解析/求值,参考如下例子,函数fn是在alert之后声明的,但是在alert执行的时候,fn已经有定义了:
alert(fn());
function fn() {
return 'Hello world!';
}
另外,还有一点需要提醒一下,函数声明在条件语句内虽然可以用,但是没有被标准化,也就是说不同的环境可能有不同的执行结果,所以这样情况下,最好使用函数表达式:
// 因为有的浏览器会返回first的这个function,而有的浏览器返回的却是第二个
if (true) {
function foo() {
return 'first';
}
} else {
function foo() {
return 'second';
}
}
foo();
// 相反,这样情况,我们要用函数表达式
var foo;
if (true) {
foo = function() {
return 'first';
};
} else {
foo = function() {
return 'second';
};
}
foo();
2.函数语句
函数语句不是在变量初始化期间声明的,而是在运行时声明的——与函数表达式一样。不过,函数语句的标识符一旦声明能在函数的整个作用域生效了。标识符有效性正是导致函数语句与函数表达式不同的关键所在
// 此刻,foo还没用声明
typeof foo; // "undefined"
if (true) {
// 进入这里以后,foo就被声明在整个作用域内了
function foo() {
return 1;
}
} else {
// 从来不会走到这里,所以这里的foo也不会被声明
function foo() {
return 2;
}
}
typeof foo; // "function"
------------------
符合标准的代码来模式上面例子中的函数语句
var foo;
if (true) {
foo = function foo() {
return 1;
};
} else {
foo = function foo() {
return 2;
};
}
----------------------------
.函数语句和函数声明(或命名函数表达式)的字符串表示类似,也包括标识符:
if (true) {
function foo() {
return 1;
}
}
String(foo); // function foo() { return 1; }
函数语句覆盖函数声明的方式不正确。在这些早期的实现中,函数语句不知何故不能覆盖函数声明:
function foo() {
return 1;
}
if (true) {
// 用函数语句重写
function foo() {
return 2;
}
}
foo(); // FF3以下返回1,FF3.5以上返回2
// 不过,如果前面是函数表达式,则没用问题
var foo = function() {
return 1;
};
if (true) {
function foo() {
return 2;
}
}
foo(); // 所有版本都返回2
3.命名函数表达式