bind(this)对函数的影响及Set中绑定函数匹配失败的解决方案咨询
JavaScript 函数绑定与集合操作问题解答
嘿,让我一步步帮你拆解这两个问题:
1. 对函数执行bind(this)时,函数会发生什么变化?
当你调用函数的bind()方法时,核心变化有这几点:
- 生成新函数,不修改原函数:
bind()会返回一个全新的函数实例,原函数本身不会有任何改变。 - 永久绑定
this上下文:新函数的this会被固定为你传入的参数,哪怕后续用call()、apply()调用这个新函数,也没法覆盖这个绑定的this。 - 支持部分参数应用:除了绑定
this,你还可以在bind()里提前传入部分参数,新函数调用时会把提前传的参数和后续传入的参数合并后传给原函数。
举个直观的例子:
const user = { username: "Mike" }; function sayHi() { console.log(`Hi, ${this.username}!`); } // 生成绑定后的新函数 const boundSayHi = sayHi.bind(user); boundSayHi(); // 输出 "Hi, Mike!" // 尝试用call修改this,无效 boundSayHi.call({ username: "Lisa" }); // 还是输出 "Hi, Mike!"
2. Set中绑定函数无法被检测到的问题分析与解决办法
问题根源
你遇到的问题核心在于**bind()每次调用都会生成一个全新的函数对象**——哪怕是对同一个原函数、同一个this调用bind(),返回的都不是同一个引用:
- 你代码里把
onceWrapper.bind(this)的返回值加到了Set里,但控制台检查的onceWrapper是原函数,和Set里的绑定函数不是同一个对象;而再次调用onceWrapper.bind(this)又会生成另一个新函数,自然和Set里的那个不匹配,所以Set.has()返回false。 - 另外,你的Set用法有误:Set是单纯的值集合,没有
add(eventName, ...)或delete(eventName, ...)这种键值对操作,如果你需要按事件名分组管理函数,应该用Map才对。 - 控制台显示
[native code]是正常现象,绑定后的函数是引擎内部创建的包装函数,它的toString()输出就是这个。
解决方案
我们需要保存bind()返回的函数引用,这样后续才能正确从集合中找到它。这里改用Map来按事件名管理函数会更合理,调整后的代码如下:
// 用Map按事件名分组管理一次性函数 const onceEventMap = new Map(); function addOnceEventListener(eventName, func) { // 先创建绑定后的函数并保存引用 const boundHandler = function() { const args = arguments; // 从对应的Set中移除当前处理函数 const handlerSet = onceEventMap.get(eventName); if (handlerSet) { handlerSet.delete(boundHandler); // 如果该事件下没有剩余函数,删除对应的Map键 if (handlerSet.size === 0) { onceEventMap.delete(eventName); } } // 执行原函数 func.apply(this, args); }.bind(this); // 绑定this并保存引用 // 初始化当前事件的Set(如果不存在) if (!onceEventMap.has(eventName)) { onceEventMap.set(eventName, new Set()); } const handlerSet = onceEventMap.get(eventName); handlerSet.add(boundHandler); // 现在检查的话会返回true console.log(handlerSet.has(boundHandler)); // true }
关键注意点
- 永远不要重复调用
bind()来获取同一个“逻辑上的绑定函数”,一定要保存第一次调用bind()返回的引用。 - 区分Set和Map的使用场景:Set适合存无分类的不重复值,Map适合键值对形式的分组管理。
- 绑定后的函数和原函数是完全独立的对象,不能用原函数去匹配Set/Map中的绑定函数。
内容的提问来源于stack exchange,提问作者alwaysnub
相关产品推荐
相关产品推荐

