通常我们定义函数会用下面两种写法:
1、函数声明
|
1
2
3
|
function test(){ //...} |
2、函数表达式
|
1
2
3
|
var test = function(){ //...}; |
表面上看没什么区别,实际上解析器会在执行任何代码前先读取声明,而函数表达式要等到解析器执行到它所在的代码行才会真正被执行。下面举个例子:
|
1
2
3
4
5
6
7
|
var test = function() { console.log(2)};function test() { //这个是函数声明,将会被提升 console.log(1);}test() |
结果是输出2,这个代码片段会被js理解为如下形式:
|
1
2
3
4
5
6
7
8
|
var test;function test() { console.log(1);}test = function() { console.log(2)};test() |
所有的声明(包括变量和函数)都会被移到作用域的顶端,这个过程叫做提升。函数表达式var test = function(){...}会被拆分成两部分,var test和test=function(){...};var test会被提升,而赋值或其他运行逻辑会留在原地。引用一下《你所不知道的JavaScript》的一段话:
当你看到var a = 2;时,可能会认为这是一个声明。但JavaScript实际上会将其看成两个声明:var a;和a = 2;。第一个定义声明是在编译阶段进行的。第二个赋值声明会被留在原地等待执行阶段。
函数声明会被提升,而函数表达式却不会被提升。
|
1
2
3
4
|
test() //函数执行写在函数声明之前是没问题的,因为函数声明会提升function test() { console.log(1);} |
|
1
2
3
4
|
test() //报错:Uncaught TypeError: test is not a functionvar test = function() { console.log(1);}; |
函数声明的使用有个值得注意的情况,应当避免:
|
1
2
3
4
5
6
7
8
9
10
|
if(true){ function test(){ alert(1) }}else{ function test(){ alert(2) }}test() |
按照这个条件判断的逻辑,返回的结果应该会是1,而按照前面介绍的声明提升说法,结果是2,函数声明会在代码执行前进行解析,先后解析function test(){ alert(1)}和function test(){ alert(2)},后面的会覆盖前面的,最后到了执行阶段调用test(),结果是返回2。其实不同浏览器在这个的表现上可能不一样,旧版本的Chrome和IE(只看了IE8)输出的结果是2,而最新版本的Chrome输出的结果是1。总之,应当避免在条件判断这样的语句下声明函数。
而表达式形式这个写法是可以的,输出的结果都是1
|
1
2
3
4
5
6
7
8
9
10
11
|
var test;if(true){ test = function (){ alert(1) };}else{ test = function (){ alert(2) };}test() |