这段代码展示了一种特殊的事件监听模式,虽然使用了数组 onCallBacks 来存储回调函数,但实际上它是在利用数组对象可以像普通对象一样通过字符串键访问属性的特性。我来详细解释这种写法:
1. 代码分析
javascript
复制
下载
this.socket.on("event_talk", (data) => {
console.log("接收到消息,event_talk", data);
new TalkEvent(data).handle();
});
onCallBacks = []; // 存储回调函数的"数组"(实际被当作对象使用)
on(event, callBack) {
this.onCallBacks[event] = callBack; // 用事件名作为"下标"
return this; // 返回this支持链式调用
}
2. 关键点解释
(1)JavaScript数组的特殊性
在JavaScript中:
-
数组本质是特殊对象,可以用字符串作为"下标"(会被隐式转换为属性名)
-
例如
arr['foo'] = 123和arr.foo = 123效果相同 -
这种写法不会影响数组的
length属性
javascript
复制
下载
const arr = [];
arr['event1'] = () => console.log('callback1');
arr['event2'] = () => console.log('callback2');
console.log(arr.length); // 0 (length不受影响)
console.log(arr.event1); // 能正常访问
(2)这种写法的实际效果
-
将事件名(如
"event_talk")作为属性名存储回调函数 -
虽然声明为数组,但实际被当作普通对象使用
-
可以通过
onCallBacks['eventName']快速查找对应的回调
(3)为什么这样写?
可能的考虑:
-
简洁性:比显式声明对象少写几个字符
-
历史原因:早期代码风格或个人习惯
-
误解:开发者可能误以为这是某种优化
3. 更规范的写法
推荐改用显式的对象形式:
javascript
复制
下载
// 更清晰的写法(推荐)
onCallbacks = {}; // 明确使用对象
on(event, callback) {
this.onCallbacks[event] = callback;
return this;
}
优势:
-
语义更明确:一看就知道是键值对存储
-
避免混淆:不会让人误以为是传统数组操作
-
性能无差异:现代JS引擎对这两种写法优化程度相同
4. 完整示例修正版
javascript
复制
下载
class SocketHandler {
constructor() {
this.socket = /* socket连接 */;
this.onCallbacks = {}; // 明确使用对象
}
// 监听socket原生事件
initSocket() {
this.socket.on("event_talk", (data) => {
console.log("接收到消息", data);
if (this.onCallbacks['event_talk']) {
this.onCallbacks['event_talk'](data); // 触发自定义回调
}
});
}
// 注册自定义回调
on(event, callback) {
this.onCallbacks[event] = callback;
return this; // 支持链式调用
}
}
// 使用示例
const handler = new SocketHandler()
.on('event_talk', data => {
console.log('自定义处理:', data);
});
5. 总结
-
原代码能工作:因为JS数组本质是对象,可以用字符串键
-
但不推荐:这种写法容易造成误解,维护性差
-
最佳实践:明确使用普通对象
{}来存储键值对 -
设计模式:这是典型的发布-订阅模式简单实现

2206

被折叠的 条评论
为什么被折叠?



