Javascript进阶(9)---函数声明与函数表达式的区别
刚开始接触JavaScript,感觉它是个弱类型的脚本语言,语法十分宽松,好学好上手。
过了一阵了,渐渐地感觉到这个脚本语言其实他并不“脚本”,也一点不“弱”。
要是你不了解他的“弱”,不了解这种脚本语言的任性,后果肯定是一次次的---“咦?明明没有错啊?这xx也行?”
JavaScript中的函数声明和函数表达式就是一个这样的例子,这两个平时我们看起来和使用起来没有什么差别的东西。
两者区别的表现
- 在JavaScript进阶(6)里面,介绍了几种“创建”函数的方法,其中头两种便是函数声明与函数表达式。
//函数声明 function funName(a, b) { //function body }
//函数表达式,他最大的特点就是像给变量赋值,只不过赋的是一个匿名的函数对象 var funName = function (a , b){ //function body };
-
在平时使用实际编程中,我们经常会把这两种方式混用,看起来没什么区别,让我们调用一下试试看
- 函数声明:
- 函数表达式:
- 用函数声明创建的函数compareAB可以在compareAB定义之前就进行调用
- 用函数表达式创建的compareAB函数不能在compareAB被赋值之前进行调用
- 到这这两种区别的原因是javascript的解释器的变量提升(Javascript hoisting)。
变量提升
In javascript, every variable declaration is hoisted to the top of its declaration context.
JavaScript解释器,会将函数的声明、变量的声明提前到作用域(上下文)的最顶部先执行,但是变量初始化(赋值)的顺序不变。
- 上例子第一种情况在JavaScript解释器中是这样进行的 使用 function 的函数声明被提前到了最顶部先执行
- 上例子第二种情况在JavaScript解释器中是这样进行的 这样看来就很容易理解了,在函数“创建”之前调用了它必然会报错
- 其他的例子
1 var myvar = 'outterValue'; 2 (function () { 3 console.log(myvar); 4 var myvar = 'innerValue'; 5 }) ();
变量提升后
1 var myvar = 'outterValue'; 2 (function () { 3 var myvar; //未进行初始化,则值为undefined 4 console.log(myvar); //输出undefined 5 myvar = 'innerValue'; 6 }) ();
- 另一个深刻理解的例子
1 var fun1; 2 console.log(typeof (fun2)); //=>function 3 console.log(typeof (anonymous)); //=>undefined 4 if (true) { 5 function fun2() { 6 console.log('我是if里面的fun2 '); 7 } 8 fun1 = function anonymous() { 9 console.log('我是if里面的 fun1'); 10 } 11 } else { 12 function fun2() { 13 console.log('我是else里面的fun2'); 14 } 15 fun1 = function anonymous() { 16 console.log('我是else里面的 fun1'); 17 } 18 } 19 fun2(); //我是else里面的fun2 20 fun1(); // 我是if里面的 fun1
从中我们可以总结几点:
- if-else语句不会形成新的作用域,变量的提升提升到了全文的顶部
- 检测到作用域内有两个同名的fun2函数的定义,第一个定义先被提升,第二个定义接着被提升(第二个定义在第一个定义之下),第二个定义覆盖了第一个fun2定义,所以fun2()是按照后者输出"我是else里面的fun2"
- 而fun1是用函数表达式创建的,其表达式的内容是在JS运行时(不是解析时)才能确定(这里条件判断就起到作用了),所以fun1表达式执行了第一个函数定义并赋值,则fun1()输出"我是if里面的 fun1"。
- 相信大家不难把js解释器里面的真实执行过程写出来
1 var fun1; 2 function fun2() { 3 console.log('我是if里面的fun2'); 4 } 5 function fun2() { 6 console.log('我是else里面的fun2'); 7 } 8 console.log(typeof (fun2)); //=>function 9 console.log(typeof (anoymous)); //=>undefined 10 if (true) { 11 //这里的fun2声明被hoisting...到了顶部 12 sayHello = function anoymous() { 13 console.log('我是if里面的 fun1'); 14 } 15 } else { 16 //这里的fun2声明被hoisting...到了顶部 17 sayHello = function anoymous() { 18 console.log('我是else里面的 fun1'); 19 } 20 } 21 fun2(); // => 我是else里面的fun2 22 fun1(); // => 我是if里面的 fun1
(以上内容改编自JackWang-CUMT的文章《详解Javascript 函数声明和函数表达式的区别》)