You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中对象的字段实例无需绑定父引用,如何调用所属上层对象的方法与属性

解答

你可以通过以下两种符合要求的方案实现需求,都不需要在FarklePlayer中存储FarkleGame实例引用,也不需要给roll()方法传递骰子实例参数:


方案1:事件驱动模式(最符合解耦要求)

JS原生支持自定义事件,你可以让FarklePlayer触发自定义事件,FarkleGame监听对应事件后执行掷骰、算分逻辑,完全解耦父子实例的直接依赖:

// 先让FarklePlayer继承EventTarget支持事件
class FarklePlayer extends EventTarget { 
  name;
  constructor(name_of_player) {
    super();
    this.name = name_of_player;
  }
  roll() {
    // 仅触发事件,不需要感知上层实例存在
    this.dispatchEvent(new CustomEvent('rollRequest'));
  }
  // 提供接收得分的方法,上层算完分后调用
  setCurrentScore(score) {
    // 这里处理玩家自身的得分逻辑
    console.log(`${this.name}本次掷骰得分:${score}`);
  }
}

class FarkleGame {
  player_one;
  player_two;
  die;
  currentPlayer; // 新增字段标记当前回合玩家

  constructor(name_of_player_one, name_of_player_two) {
    this.player_one = new FarklePlayer(name_of_player_one);
    this.player_two = new FarklePlayer(name_of_player_two);
    this.die = new FarkleDie();
    this.currentPlayer = this.player_one;
    // 监听两个玩家的掷骰请求事件
    this.player_one.addEventListener('rollRequest', () => this.handlePlayerRoll());
    this.player_two.addEventListener('rollRequest', () => this.handlePlayerRoll());
  }
  // 统一处理玩家掷骰请求
  handlePlayerRoll() {
    this.die.rolled();
    const score = this.score_die();
    this.currentPlayer.setCurrentScore(score);
  }
  // 修复原代码语法错误,补充返回值
  score_die() {
    let die_value = this.get_die().get_value();
    let score = ((die_value * die_value) * 10) - 1;
    return score;
  }
  get_player_one() { return this.player_one; }
  get_player_two() { return this.player_two; }
  get_die() { return this.die; }
}

class FarkleDie {
  value;
  constructor() { this.value = null; }
  rolled() { this.value = Math.floor(Math.random() * 6) + 1; }
  get_value() { return this.value; } // 补充原代码缺失的取值方法
}

使用示例:

const game = new FarkleGame('张三', '李四');
// 当前玩家发起掷骰请求,自动触发上层的掷骰、算分逻辑
game.get_player_one().roll();

方案2:构造期注入绑定(轻量化实现)

如果你不想用事件,也可以在FarkleGame构造实例时,给FarklePlayer绑定定制化的roll方法实现,不需要Player类感知上层实例:

class FarklePlayer { 
  name;
  roll; // 预留roll方法位,由上层实例注入实现
  constructor(name_of_player) {
    this.name = name_of_player;
  }
}

class FarkleGame {
  player_one;
  player_two;
  die;

  constructor(name_of_player_one, name_of_player_two) {
    this.die = new FarkleDie();
    // 构造Player时直接注入roll方法的实现,绑定当前game实例上下文
    this.player_one = new FarklePlayer(name_of_player_one);
    this.player_one.roll = () => {
      this.die.rolled();
      const score = this.score_die();
      console.log(`${this.player_one.name}得分:${score}`);
    };
    this.player_two = new FarklePlayer(name_of_player_two);
    this.player_two.roll = () => {
      this.die.rolled();
      const score = this.score_die();
      console.log(`${this.player_two.name}得分:${score}`);
    };
  }
  // 其余方法和FarkleDie类代码同方案1,补充修复后的score_die、get_value方法即可
  get_player_one() { return this.player_one; }
  get_player_two() { return this.player_two; }
  get_die() { return this.die; }
  score_die() {
    let die_value = this.get_die().get_value();
    let score = ((die_value * die_value) * 10) - 1;
    return score;
  }
}

说明

两种方案都满足你要求的不在FarklePlayer中存储FarkleGame实例引用、不给roll方法传骰子参数的前提,事件驱动方案更适合复杂的多交互场景,注入方案更适合简单的轻量化场景。

内容的提问来源于stack exchange,提问作者Rar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 04:06:04