先看以下几段烧脑的代码:
1 2 3 4 5 6 7 8 | f(); //=>? var f = function () { console.log( "var" ); } function f() { console.log( "function" ); } |
控制台打印结果"function"。
另一段代码
1 2 3 4 5 6 7 8 | var f = function () { console.log( "var" ); } function f() { console.log( "function" ); } f(); //=>? |
控制台打印结果"var"。
关于函数声明和函数表达式更具体的定义在javascript函数中有相关详细的介绍,这里就不再叙述。上述代码主要用于引出函数声明和函数表达式的区别。
函数声明和函数表达式的区别本质其实是函数声明提升和变量声明提升的区别。
一般变量的声明为以下形式:
js在预编译阶段,是这么处理的:
1 2 3 4 | //预编译阶段 var a; //执行阶段 a=10; |
预编译阶段,js将其分解为变量声明与变量赋值。
一般函数声明:
1 2 3 | function fDeclaration(){ console.log( "declaration" ); } |
预编译阶段,js将其分解为类似以下的变量声明与变量赋值:
1 2 3 4 5 | //预编译 var fDeclaration; fDeclaration = function () { console.log( "declaration" ); } |
在标识符相同的情况下,js如何处理变量与函数呢?
1 2 3 4 5 6 7 | var f = function () { console.log( "var" ); } function f() { console.log( "function" ); } f(); //=> 在控制台会打印什么结果呢? |
函数声明提前优先于变量声明提前。因此上面代码JS预编译会做类似如下处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* 预编译阶段 *函数声明提前优先级别更高,先进行预编译,并对f进行了赋值。 *在预编译阶段后于函数声明,f经历两次赋值,后来的赋值替代了原先的赋值,表现为f执行函数表达式。 */ //函数声明预编译阶段 var f; f = function () { console.log( "function" ); } //函数表达式提前预编译,由于它是变量声明,变量声明提前是只有声明提前,而没有赋值提前。 //重复的声明,js会忽略 var f; /*执行阶段*/ //变量f再次赋值 f = function () { console.log( "var" ); } f(); //=>"var" |