创建函数

101 阅读3分钟

一、函数声明(Function Declaration)

function add(a, b) {
  return a + b;
}
  • 特点
    • 函数提升:可在声明前调用(JS 引擎会将函数声明提升到当前作用域顶部)。
    • 命名函数:函数名自动绑定到当前作用域,便于递归或调试。
  • 适用场景:需要全局可用或递归调用的函数。

二、函数表达式(Function Expression)

const subtract = function(a, b) {
  return a - b;
};
  • 特点
    • 变量赋值:函数需先赋值给变量才能调用,无提升。
    • 匿名函数:函数体可不命名(但可通过 subtract.name 获取变量名)。
  • 变种:具名函数表达式(如 function namedSubtract(a, b) {...}),用于内部递归。

三、箭头函数(Arrow Function)

const multiply = (a, b) => a * b;
  • 特点
    • this 绑定:继承外层作用域的 this(适合回调函数,避免 this 指向问题)。
    • 隐式返回:单行表达式可省略 return 和大括号。
    • 不能使用 argumentsyield:需通过剩余参数 ...args 访问参数。
  • 适用场景:无状态的纯函数、DOM 事件处理、数组方法回调。

四、构造函数(Function Constructor)

const divide = new Function('a', 'b', 'return a / b;');
  • 特点
    • 动态生成:函数体作为字符串传入,运行时编译(性能较差)。
    • 全局作用域:生成的函数总是在全局作用域中执行。
  • 应用场景:动态生成代码(如配置解析),但存在安全风险(类似 eval)。

五、Generator 函数(ES6)

function* fibonacci() {
  let a = 0, b = 1;
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}
  • 特点
    • 暂停执行:通过 yield 关键字暂停函数执行,返回迭代器。
    • 状态保存:每次调用 next() 时恢复执行上下文。
  • 适用场景:异步流控制(如 async/await 底层实现)、无限序列生成。

六、Class 方法(ES6)

class Calculator {
  add(a, b) {
    return a + b;
  }
  
  static subtract(a, b) { // 静态方法
    return a - b;
  }
}
  • 特点
    • 原型链继承:实例方法挂载到 prototype,静态方法挂载到类本身。
    • 构造函数:通过 constructor 初始化实例属性。
  • 适用场景:面向对象设计,封装状态和行为。

七、高频

1. 问:箭头函数与普通函数的区别?

    • this 指向:箭头函数继承外层 this,普通函数 this 取决于调用方式。
    • 构造能力:箭头函数不能使用 new 实例化,无 prototype
    • 语法:箭头函数更简洁,支持隐式返回。

2. 问:函数提升的原理是什么?

    • JS 引擎在编译阶段会将函数声明添加到当前作用域,而变量赋值(如函数表达式)在执行阶段才处理。
    • 示例:
      add(2, 3); // 5(函数声明可提升)
      const sub = subtract(5, 2); // 错误:subtract 未定义(表达式无提升)
      
      function add(a, b) { return a + b; }
      const subtract = function(a, b) { return a - b; };
      

3. 问:何时使用构造函数创建函数?

    • 极少使用!因字符串解析存在安全风险(如代码注入)且性能差。
    • 唯一优势是可动态生成函数(如从配置文件读取函数体),但建议用 eval 替代。

4. 问:Generator 函数的应用场景?

    • 异步编程:结合 co 库实现早期的异步流程控制(现代已被 async/await 替代)。
    • 自定义迭代器:生成无限序列(如斐波那契数列)或惰性计算数据。