浅谈js函数声明与函数表达式

我们都知道js的函数声明是用关键字function声明的,如下面这个最简单的声明:

function num(){
    return 10;
}

在js中,函数实际上就是一个对象,它是Function构造函数的实例,并且与其他引用类型一样有属性和方法,所以函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。


下面以函数表达式的方式来定义函数,代码如下:

var num = function(){
    return 10;
}

这与上面的function关键字声明基本上是一样的,但在解析上却有点不同。实际上,函数声明(即function后面加上函数名的方式)在解析的时候,解析器会把函数声明提升,并使其在执行任何代码之前可用,我们来看个示例:

console.log(num());
function num(){
    return 10;
}

pic1.png

结果打印出10。解析器在解析的时候内部把代码转换成

function num(){
    return 10;
}
console.log(num());


至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解析执行,看下面的例子:

console.log(num);
var num = function(){
    return 10;
}

pic2.png

报错了(不是函数),说明在解析到console行的时候并没有找到前面声明的num函数,这也表明了函数表达式是不能声明提升的。


如果同时使用函数声明和函数表达式又会怎么解析呢,如下面的代码:

console.log(num());
function num(){
    return 10;
}
var num = function(){
    return 20;
};

pic1.png

打印出10,这是由于函数声明提升的原因,好理解。


那如果把console放在最后面

function num(){
    return 10;
}
var num = function(){
    return 20;
};
console.log(num());

pic3.png

结果是20,为什么会不一样?我们把代码转换一下就容易理解了:

var num = function(){
    return 10;
};
var num = function(){
    return 20;
};
console.log(num());

刚开始num是指向return10的那个函数,但在下面又改为指向return20的那个函数,那么返回的自然就是20;

在这种情况下,解析器并不会真正转换代码,这里我只是为了方便说明而做的转换,这样看起来一目了然。而真正的原理就是num指针指向的改变。