JavaScript循环内函数声明性能对比:箭头函数vs外部函数
高频调用函数的实现疑问解答
问题背景
我有一个activeElemFromPoint函数,会在鼠标移动时被频繁调用,现有三种实现方案,同时有两个技术疑问:
- 是否必须使用方案3(循环外部定义函数)?
- 函数
hasEvtNoAttr的两种声明方式3.1和3.2是否等价?
三种实现方案
方案1:箭头函数实现
/** @param { {clientX:number, clientY:number} } evt */ export function activeElemFromPoint(evt) { return document .elementsFromPoint(evt.clientX, evt.clientY) .find(el => !el.hasAttribute('data-evt-no')); }
方案2:循环内定义普通函数实现
/** @param { {clientX:number, clientY:number} } evt */ export function activeElemFromPoint(evt) { return document .elementsFromPoint(evt.clientX, evt.clientY) .find(function (el) { return !el.hasAttribute('data-evt-no'); }); }
方案3:循环外部定义函数实现
/** @param { {clientX:number, clientY:number} } evt */ export function activeElemFromPoint(evt) { return document .elementsFromPoint(evt.clientX, evt.clientY) .find(hasEvtNoAttr); } // 3.1 /** @param {Element} el */ const hasEvtNoAttr = (el) => !el.hasAttribute('data-evt-no'); // 3.2 function hasEvtNoAttr(el) { return !el.hasAttribute('data-evt-no'); }
已知方案1每次调用时都会创建新的函数。
问题解答
1. 是否必须使用方案3?
不是必须的,但方案3在高频调用场景下有性能优势:
- 方案1和2每次调用
activeElemFromPoint时,都会在find方法内部创建新的函数实例。现代JS引擎对这类小函数的创建和回收有不错的优化,普通场景下几乎感知不到差异,但鼠标移动这类每秒可能触发数十到上百次调用的场景中,累计的内存分配和垃圾回收压力会被放大。 - 方案3把判断函数提取到外部,每次
find都复用同一个函数实例,能减少不必要的内存开销,性能敏感场景更推荐使用。 - 如果项目对性能要求没那么极端,方案1/2的写法更简洁直观,可读性更高,完全可以正常使用。
2. hasEvtNoAttr的两种声明方式是否等价?
在当前业务场景下功能完全等价,但两者在JS语言特性上存在细微差异:
- 变量提升:3.2的
function声明会被变量提升,在代码中声明位置之前就能调用;而3.1的const箭头函数不会提升,必须在声明之后才能使用。 this绑定:箭头函数没有自身的this,会继承外层作用域的this;普通函数的this由调用方式决定。但在这个场景里,find方法仅传递遍历到的元素作为参数,不会用到this,所以不影响功能。- 可修改性:3.1用
const声明,无法被重新赋值;3.2的function声明本质是给变量赋值,在非块级作用域中可以被重新覆盖。
内容的提问来源于stack exchange,提问作者user1167761
相关产品推荐
相关产品推荐

