如何在类方法中同时访问WebSocket实例与类自身实例?
WebSocket流管理类:同时访问类实例与WebSocket实例的简洁方案
问题背景
现有一个管理多WebSocket连接的Stream类,需要在open、close等事件回调中同时访问Stream类实例(获取params、ws数组等)和触发事件的WebSocket实例(调用send、定位连接等)。
原始类代码如下:
class Stream implements IStream { private ws: WebSocket[] = [] private params: string[] = [] private streamCount: number = 2 private url: string; // 补充缺失的属性定义 constructor(url: string, params: string[]) { this.url = url this.params = params } private _onOpen() { // 需求:this → WebSocket实例,同时拿到Stream实例的params this.send( JSON.stringify({ params: that.params }) ) } private _onMessage(msg: Buffer) { const jsonObj = JSON.parse(msg.toString()) console.log(jsonObj) } private _onClose(msg) { console.error(msg) // 需求:this → WebSocket实例,同时拿到Stream实例的ws数组和url const idx = that.ws.indexOf(this) that.ws[idx] = new WebSocket(that.url) } private _setWsListener(ws: WebSocket) { ws.on('error', console.error) ws.on('open', this._onOpen) ws.on('message', this._onMessage) ws.on('close', this._onClose) } public listen() { for (let i = 0; i < this.streamCount; i++) { const conn = new WebSocket(this.url) this._setWsListener(conn) this.ws.push(conn) } } }
尝试过两种方案但都有弊端:
- 使用
bind(this)绑定类实例,但无法访问WebSocket实例; - 让回调函数返回匿名函数,虽能解决问题但代码冗余复杂。
简洁解决方案
方案1:箭头函数包裹+直接传参
利用箭头函数的词法作用域特性(箭头函数内的this指向外层的Stream实例),在绑定事件时直接将WebSocket实例作为参数传入回调:
class Stream implements IStream { private ws: WebSocket[] = [] private params: string[] = [] private streamCount: number = 2 private url: string; constructor(url: string, params: string[]) { this.url = url this.params = params } private _onOpen(ws: WebSocket) { // this → Stream实例,ws → WebSocket实例 ws.send( JSON.stringify({ params: this.params }) ) } private _onMessage(msg: Buffer) { const jsonObj = JSON.parse(msg.toString()) console.log(jsonObj) } private _onClose(msg: any, ws: WebSocket) { console.error(msg) // this → Stream实例,ws → WebSocket实例 const idx = this.ws.indexOf(ws) if (idx !== -1) { this.ws[idx] = new WebSocket(this.url) this._setWsListener(this.ws[idx]) } } private _setWsListener(ws: WebSocket) { ws.on('error', console.error) // 用箭头函数包裹,同时传入ws实例 ws.on('open', () => this._onOpen(ws)) ws.on('message', (msg) => this._onMessage(msg)) ws.on('close', (msg) => this._onClose(msg, ws)) } public listen() { for (let i = 0; i < this.streamCount; i++) { const conn = new WebSocket(this.url) this._setWsListener(conn) this.ws.push(conn) } } }
方案2:bind绑定类实例+预置参数
通过bind同时绑定Stream实例为回调的this,并将WebSocket实例作为预置参数传入回调:
class Stream implements IStream { private ws: WebSocket[] = [] private params: string[] = [] private streamCount: number = 2 private url: string; constructor(url: string, params: string[]) { this.url = url this.params = params } private _onOpen(ws: WebSocket) { // this → Stream实例,ws → WebSocket实例 ws.send( JSON.stringify({ params: this.params }) ) } private _onMessage(msg: Buffer) { const jsonObj = JSON.parse(msg.toString()) console.log(jsonObj) } private _onClose(ws: WebSocket, msg: any) { console.error(msg) // this → Stream实例,ws → WebSocket实例 const idx = this.ws.indexOf(ws) if (idx !== -1) { this.ws[idx] = new WebSocket(this.url) this._setWsListener(this.ws[idx]) } } private _setWsListener(ws: WebSocket) { ws.on('error', console.error) // bind绑定this为Stream实例,同时预置ws为第一个参数 ws.on('open', this._onOpen.bind(this, ws)) ws.on('message', this._onMessage.bind(this)) ws.on('close', this._onClose.bind(this, ws)) } public listen() { for (let i = 0; i < this.streamCount; i++) { const conn = new WebSocket(this.url) this._setWsListener(conn) this.ws.push(conn) } } }
方案说明
两种方案都无需额外嵌套函数,代码简洁直观:
- 箭头函数方案更符合现代TS写法,可读性强;
bind方案适合习惯传统函数绑定写法的场景。
同时补充了原始类中缺失的url属性定义,避免运行时错误。
内容的提问来源于stack exchange,提问作者user3077593
相关产品推荐
相关产品推荐

