• 函数声明与函数表达式


    突然发现,虽然天天都写,但是这里头还有不少东西很模糊,放一下自己的探索过程。

    创建普通函数的方式

    此次只讨论该两种形式:

    • 函数声明
      function add(a, b) {
          return a + b;
      }
      
      • 1
      • 2
      • 3
    • 函数表达式
      const add = (a, b) => a + b;
      
      • 1

    接下来对比一下两者之间差异,也许很多地方看起来都很针对函数声明。

    函数提升

    使用函数声明方式创建的函数,可以在其有效作用域的任何位置进行使用,包括函数声明之前使用也是可以的,这便是函数提升。

    // OK
    console.log(add(10, 20)); // 30
    
    function add(a, b) {
      return a + b;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    而函数表达式并不存在这个规则,其遵从变量声明规则:

    // Err
    console.log(add(10, 20));
    
    const add = (a, b) => a + b;
    
    • 1
    • 2
    • 3
    • 4

    那能不能用 var 进行声明,让其提升呢?不行,var 声明的变量只是变量本身提升了,值是不会跟上的,只能说你可以找到变量,但是在达到声明语句之前,都只是 undefined

    重复声明

    对于函数声明来说,是可以存在重复声明的,当存在重复声明时,最终落实的是最后一个函数:

    console.log(add(10, 20)); // 0
    
    // 被后者覆盖
    function add(a, b) {
      return a + b;
    }
    // 该函数生效
    function add(a, b) {
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    好,这个了解到了,那么再扩展一下:

    如果在其中插入一个同名变量会怎么样,请问谁会覆盖谁?(分别给出 varconst 两者的执行结果)

    先回答 const 的表现:但凡使用 const 导致重复声明(包括与函数名称冲突),统一异常停止。

    至于 var,那就很有意思了,首先是,可以共存

    console.log(add); // [Function: add]
    console.log(add(10, 20)); // 0
    
    var add = "add";
    
    console.log(add); // "add"
    
    function add(a, b) {
      return a + b;
    }
    
    function add(a, b) {
      return 0;
    }
    
    console.log(add); // "add"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    可以看出,在达到变量声明之前,add 这个名称都归第二个函数所有,而变量完成声明之后,就成了字符串 "add"

    至于为什么执行经过了函数声明却没有任何变化,因为函数声明语句在一开始就已经执行好了。

    那么函数表达式呢,其表现已经在扩展题当中提到了:

    console.log(add); // undefined
    
    var add = (a, b) => a + b;
    
    console.log(add(10, 20)); // 30
    
    var add = () => 0;
    
    console.log(add(10, 20)); // 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    当然,该表现只要知道 var 的行为逻辑就很容易理解。而对于函数表达式来说,通常都是 const 声明,所以通常不会存在重复声明问题,该问题也是需要自己避免的。

    选择

    这么看下来,你就是想捧函数表达式吧?

    至少我个人更习惯如此,并不需要函数提升,先有声明再使用也符合正常。

    函数表达式并不存在 this 问题,没用规定说函数表达式都是箭头函数形式是吧,而使用箭头函数恰恰是用来解决 this 绑定问题的。

    函数声明 & 函数表达式

    我在想反例时,发现好像有一种奇怪的存在,那就是非箭头函数形式的函数表达式:

    const add = function (a, b) {
      return a + b;
    }
    
    • 1
    • 2
    • 3

    因为我突然想起来,这个函数好像可以取一个名字,只是说多数情况下,不会特意给其一个名称,因为没什么意思。

    但现在回头看,真的会没用吗,就想试试水,因为记得一规范指南当中提到,这是最推荐的写法(虽然我一直都没有照做)。

    在这里插入图片描述

    const fn = function add(a, b) {
      console.log(a, b);
    };
    
    console.log(fn); // [Function: add]
    console.log(add); // ReferenceError: add is not defined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    啊,这种写法导致函数声明不起效果,根本找不到 add。不过慢着,这个函数叫什么来着,居然是 [Function: add]?于是尝试在 add() 函数体内找 add,居然真的可以:

    const fn = function add(a, b) {
      console.log(add); // [Function: add]
      return a + b;
    };
    
    console.log(fn(1, 2)); // 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    哇,看似好像发现了一个什么了不得的东西,但是别急,在这个场景下是没用的。若是真的想递归调用,可以选择直接找 fn(),而不需要在内部找。

    当然,也可以这么玩:

    (function dfs(n) {
      if (n === 0) {
        return;
      }
      dfs(n - 1);
      console.log(n);
    })(5);
    // 1
    // 2
    // 3
    // 4
    // 5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    -END-

  • 相关阅读:
    Arm 警告其 GPU 驱动漏洞正被活跃利用
    人力物力和时间资源有限?守住1个原则,精准覆盖所有兼容性测试!
    Java岗吃透这份pdf,拿下阿里、腾讯等大厂offer
    【LLM模型篇】LLaMA2 | Vicuna | EcomGPT等
    Postman —— HTTP请求基础组成部分
    【REACT-router】
    union
    Y4455芯片开发的433遥控流水灯方案
    1388. 3n 块披萨
    Linux命令(123)之mail
  • 原文地址:https://blog.csdn.net/qq_49661519/article/details/126858679