函数声明和函数表达式的区别

函数声明(funDeclaration)

无论在哪儿定义函数,只要是外层函数并且满足不被包裹,就都可以进行全局范围的调用

1
function foo() { }

在函数体内部的函数声明无法提升到全局,只能提升到函数体内顶部(块级作用域空间)

1
2
3
4
5
6
7
8
9
10
function test() {
console.log(1);

function test2() {
console.log(2);
}

}
test(); // 1
test2(); // Uncaught ReferenceError: test2 is not defined

函数体内部执行:

1
2
3
4
5
6
7
8
function test() {

test2();
function test2() {
console.log(2);
}
}
test(); // 2

在外部要想访问函数内部申明的函数,需要先return出来:

1
2
3
4
5
6
7
8
9
10
11
function test() {
console.log(1);

function test2() {
console.log(2);
}
return {
test2:test2
}
}
test().test2(); // 2

函数表达式(funExpression)

函数表达式需要等到表达式赋值 完成 才可以

换言之使用var来声明函数,就会涉及到变量的声明提升,先拿出变量名定义为undefined,再随着逻辑顺序进行赋值先定义,后使用

1
var foo = function () { }

demo1

1
2
3
4
5
6
7
8
9
10
Toast()    // hello world

showToast(); // shwoToast is not a function

var showToast = function () {
console.log('123')
}
function Toast() {
console.log('hello world')
}

在这里只需要把showToast提前就好了

demo2

主流浏览器解析,ie11+

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var sayHello;
console.log(typeof (sayHey));//=>undefined
console.log(typeof (sayHo));//=>undefined
if (true) {
function sayHey() {
console.log("sayHey");
}
sayHello = function sayHo() {
console.log("sayHello");
}
} else {
function sayHey() {
console.log("sayHey2");
}
sayHello = function sayHo() {
console.log("sayHello2");
}
}
sayHey();// => sayHey
sayHello();// => sayHello

在花括号里面声明的函数在进行预解析时只会提升函数名,不会提升函数体,所以不管if条件是否为真,函数体都不会提升,永远是undefined,接下来随着if条件判断进行解析赋值,当然是走ture方法。

ie9,ie10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var sayHello;
console.log(typeof (sayHey));//=>function
console.log(typeof (sayHo));//=>undefined
if (true) {
function sayHey() {
console.log("sayHey");
}
sayHello = function sayHo() {
console.log("sayHello");
}
} else {
function sayHey() {
console.log("sayHey2");
}
sayHello = function sayHo() {
console.log("sayHello2");
}
}
sayHey();// => sayHey2
sayHello();// => sayHello

在这里的ie将所有的函数声明进行了提升,从而由sayHey2替代了sayHey,函数表达式的在顺着条件判断进行了定义,执行为true的情况,进行赋值解析。

ie8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var sayHello;
console.log(typeof (sayHey));//=>function
console.log(typeof (sayHello));//=>function
if (true) {
function sayHey() {
console.log("sayHey");
}
sayHello = function sayHo() {
console.log("sayHello");
}
} else {
function sayHey() {
console.log("sayHey2");
}
sayHello = function sayHo() {
console.log("sayHello2");
}
}
sayHey();// => sayHey2
sayHello();// => sayHello

ie8在这里处理的比较奇葩,正常的函数申明提升,但是却也将条件判断为假的情况进行了提升,我们看到typeof (sayHello)=>function

结论

由于函数声明提升的差异,想要在条件判断中定义不同的函数方法,应该采用定义函数表达式的方法,这样就在各个浏览器中拿到相同的函数方法,得到相同的结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var sayHello;
console.log(typeof (sayHey));//=>undefined ie8以下解析为function
console.log(typeof (sayHo));//=>undefined
if (true) {
var sayHey =function sayHey() {
console.log("sayHey");
}

} else {
var sayHey =function sayHey() {
console.log("sayHey2");
}

}
sayHey();// => sayHey

参考