函数声明式
- 重复调用性能:函数声明式在解析阶段就被提升到作用域顶部,重复调用时,函数已经存在于作用域中,直接调用即可,性能相对较好。
- 闭包场景:闭包形成时,函数声明式会保持对其所在作用域的引用。如果闭包长时间存在,可能导致其引用的外部作用域变量无法被垃圾回收,从而引发内存泄漏。
- 示例:
function add(a, b) {
return a + b;
}
// 多次调用
for (let i = 0; i < 1000; i++) {
add(i, i + 1);
}
函数表达式
- 重复调用性能:函数表达式在执行到定义它的语句时才会被创建,所以第一次调用时会有创建函数的开销。但后续重复调用与函数声明式类似,直接调用已创建的函数。
- 闭包场景:同样会保持对所在作用域的引用。不过,由于其定义和调用相对灵活,在某些复杂闭包场景下,可能更容易控制作用域和变量的生命周期,相对减少内存泄漏风险。
- 示例:
let multiply = function (a, b) {
return a * b;
};
// 多次调用
for (let i = 0; i < 1000; i++) {
multiply(i, i + 1);
}
箭头函数
- 重复调用性能:箭头函数与函数表达式类似,在执行到定义处创建,后续重复调用直接执行。但箭头函数没有自己的
this
、arguments
等,在某些场景下代码执行可能更简洁,性能略有优势。
- 闭包场景:箭头函数本身不会创建新的作用域,它的
this
继承自外层作用域,所以在闭包场景下,对作用域的引用情况相对简单清晰。但如果不小心,可能会因不正确的 this
绑定导致逻辑错误和潜在内存问题。
- 示例:
let divide = (a, b) => a / b;
// 多次调用
for (let i = 0; i < 1000; i++) {
divide(i, i + 1);
}
选择合适声明方式避免内存泄漏
- 简单逻辑且频繁调用:对于简单的、频繁调用的函数,函数声明式可能是较好的选择,因为其提升特性在多次调用时性能稍优,如一些工具函数。
- 复杂闭包逻辑:在复杂闭包场景下,函数表达式可能更合适,因为可以通过合理安排函数定义位置和作用域控制,减少不必要的作用域引用,降低内存泄漏风险。
- 简洁语法和特定
this
需求:如果需要简洁的语法并且 this
继承自外层作用域的场景,箭头函数是不错的选择。但要注意 this
绑定是否符合预期,避免因 this
问题导致潜在内存问题。例如在事件处理函数中,若不需要改变 this
指向,箭头函数简洁明了。
// 事件处理示例
let button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Clicked!');
});