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 函数声明和函数表达式的区别》)

原文地址:https://www.cnblogs.com/HXW-from-DJTU/p/5983511.html