JavaScript OOP中如何通过父类实例访问同级子类实例的属性
关于循环引用的问题
现代JavaScript环境(浏览器、Node.js)均采用标记清除的垃圾回收算法,你提到的循环引用结构不会导致内存泄漏,仅在你需要把实例序列化为JSON时才会报错,只要主动规避序列化场景即可正常使用,不需要过度担心。
利用继承实现需求的方案
你当前的类继承逻辑没有发挥作用,核心原因是Player和作为游戏管理器的GameObject本身是从属关系而非同类型的父子类关系,可以通过父类静态属性的共享特性来实现需求:
方案1:父类静态属性存储全局玩家列表(单游戏实例场景最优)
将玩家列表挂载到GameObject的静态属性上,所有继承自GameObject的子类实例都可以直接访问该共享列表,不需要传递实例、不存在循环引用,完全用到继承的能力:
class GameObject { // 静态属性,所有实例共享,存储全局玩家列表 static players = [] constructor(gameMap) { this.gameMap = gameMap } init() { // 实例化玩家后直接存入静态数组 GameObject.players.push(new Player(this.gameMap, 'Alice', {x: 10, y: 20})) GameObject.players.push(new Player(this.gameMap, 'Bob', {x: 50, y: 80})) } playGame() { GameObject.players.forEach(player => player.play()) } } class Player extends GameObject { constructor(gameMap, name, position) { super(gameMap) this.name = name this.position = position } play() { this.getOpponentPos() } getOpponentPos() { // 过滤出非自身的玩家即为对手,实时取最新的position属性 const opponent = GameObject.players.find(p => p.name !== this.name) console.log(`${opponent.name} 当前位置: x=${opponent.position.x}, y=${opponent.position.y}`) } }
方案2:优化原有传实例方案(多游戏实例场景最优)
如果需要同时运行多个独立的游戏实例,静态属性会导致玩家列表冲突,此时你原本的传递游戏实例的方案更灵活,只需要增加自定义序列化逻辑规避循环引用的报错即可:
class Player extends GameObject { constructor(gameMap, name, position, gameObj) { super(gameMap) this.name = name this.position = position // 存储所属游戏实例 this.currentGame = gameObj } // 自定义序列化逻辑,排除循环引用的currentGame字段 toJSON() { const { currentGame, ...rest } = this return rest } getOpponentPos() { const opponent = this.currentGame.players.find(p => p.name !== this.name) console.log(`${opponent.name} 当前位置: x=${opponent.position.x}, y=${opponent.position.y}`) } }
内容的提问来源于stack exchange,提问作者Niv
相关产品推荐
相关产品推荐

