通常我们定义函数会用下面两种写法:
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 function var 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() |