函数和变量的声明总是会被解析器悄悄地被“提升”到方法体的最顶部

上面是javascript变量提升的概念。为了更好地理解“变量提升”,我们先来看一段代码:

(function (){
    console.log(foo);
    var foo = "Javascript";
})();

控制台输出:undefined 为什么输出了undefined,而没有报错呢?

原来javascript是函数作用域,解析器会在函数开头处自动去声明局部变量,局部变量都会被放在函数的入口处定义,所以上面的代码实际会被解释成:

(function (){
 	var foo;
    console.log(foo);
    foo = "Javascript";
})();

另外,需要注意Javascript中函数的两种声明方式存在的坑:

对于函数声明式,解析器会确保在所有代码执行之前声明已经被解析。而对于函数表达式,与定义其它基本类型变量一样,逐句执行并解析。

我们再来举个栗子:

/* 函数声明式 */
(function(){
	fn();
	function fn() {
		console.log('来自函数声明式fn');
	}
})();

/* 函数表达式 */
(function(){
	fn();
	var fn = function() {
		console.log('来自函数表达式fn');
	}
})();

控制台依次输出:

来自函数声明式fn
fn is not a function

可以看到,当使用函数声明的形式来定义函数时,可将调用语句写在函数声明之前,而后者,则会报错。

所以在Javascript中,变量的声明会被提升,而变量的赋值则不会。而函数的声明与变量的声明是不一样的,函数的函数体也会被一起提升,但请使用函数声明的形式才能提升。