一、函数声明(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 和大括号。
- 不能使用
arguments、yield:需通过剩余参数 ...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);
const sub = subtract(5, 2);
function add(a, b) { return a + b; }
const subtract = function(a, b) { return a - b; };
3. 问:何时使用构造函数创建函数?
- 答:
- 极少使用!因字符串解析存在安全风险(如代码注入)且性能差。
- 唯一优势是可动态生成函数(如从配置文件读取函数体),但建议用
eval 替代。
4. 问:Generator 函数的应用场景?
- 答:
- 异步编程:结合
co 库实现早期的异步流程控制(现代已被 async/await 替代)。
- 自定义迭代器:生成无限序列(如斐波那契数列)或惰性计算数据。