关于函数声明与函数表达式的一些理解

通常我们定义函数会用下面两种写法:

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 testtest=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()
posted @ 2017-08-30 10:39  莫笑我胡为  阅读(214)  评论(0编辑  收藏  举报