【问题标题】:Modifying variables in subclass instances修改子类实例中的变量
【发布时间】:2017-07-11 14:21:20
【问题描述】:

我最近对 ​​Screeps 上瘾了,我重构了一些代码以创建基于任务的实现。任务是诸如“步行然后收获直到你满负荷”之类的东西,它基于一个编写为 ES6 样式类的单个基本任务模板。 Creeps 可以通过加载相关任务文件并返回新任务实例的包装器 (tasks.js) 分配任务。

今天我遇到了一个奇怪的错误,让我觉得我没有完全理解 Javascript 的继承模型。下面是相关代码:

Task.js:(基础任务类)

class Task {
    constructor(taskName) {
        // Parameters for the task
        this.name = taskName; // name of task
        this.quiet = false; // suppress console logging if true
        this.creep = [creep assigned to this task]
        this.target = [thing task operates on, e.g. "repair this wall"]
        ...
    }
    ...
    // Execute this task each tick. Returns nothing unless work is done.
    step() {
        ...
        if (creep.pos.inRangeTo(target, this.targetRange)) {
            var workResult = this.work();
            console.log(this.quiet) // < returns false, should be true?
            if (workResult != OK && this.quiet == false) {
                creep.log("Error: " + workResult); // < is printed when run
            }
            return workResult;
        } [else move to target]
    }
    ...
    // Task to perform when at the target
    work() {
        // overwrite this in child class
    }
}

module.exports = Task;

task_harvest.js:(收获任务)

var Task = require('Task');

class taskHarvest extends Task {
    constructor() {
        super('harvest');
        // no mention of this.quiet here
    }
    ...
    work() {
        console.log("harvest:" + this.quiet);
        return this.creep.harvest(this.target);
    }
}
module.exports = taskHarvest;

tasks.js:(通过函数调用生成新任务实例的包装器)

module.exports = function (taskName) {
    var TaskClass = require('task_' + taskName); // all tasks follow this naming pattern
    var taskInstance = new TaskClass;
    return taskInstance;
};

harvester.js:(收割机蠕变的行为模型)

var tasks = require('tasks');
var roleHarvester = {
    ...
    harvest: function (creep) {
        var target = Game.getObjectById(creep.memory.assignment);
        var taskHarvest = tasks('harvest');
        taskHarvest.quiet = true;  // < this task shouldn't print anything
        creep.assign(taskHarvest, target); // assigns to creep.task
        return OK;
    },
    ...
    run: function (creep) { // executed every tick
        // execute the task
        creep.task.step();
    },
   ...
}

当我分配一个从源中获取的cree 时,我从task_harvest.js 创建一个新任务,将其quiet 属性设置为true,并将它及其目标绑定到cree。一旦cree有一个任务,它就会被指示运行它,直到它变得无效(代码未包含在上面)。 Cree 可以正常执行任务,但仍会将所有内容记录到控制台。

我认为在harvester.js 中,当我设置taskHarvest.quiet = true; 时,从Task.js 导入的行为会将this.quiet 视为true。然而,似乎情况并非如此。在roleHarvester 中,运行console.log(creep.task.quiet) 返回true,但在Task 中,当cree 执行分配的任务时运行console.log(this.quiet) 会得到false

我可以将quiet 作为可选参数添加到构造函数中,但这很复杂,我想知道为什么我正在做的事情不起作用。

【问题讨论】:

  • 当您检查this.quiet 的值时,您是否100% 确定this 是正确的?对于你的继承权,我看不出有任何明显的错误或误解。设置taskHarvest.quiet = true; 应该可以正常工作。
  • @jfriend00 在Task.js 中,this 应该引用Task,在task_harvest.js 中,this 应该引用taskHarvest,它没有定义this.quiet,所以它应该引用继承的 Task.js 变量。然后,当我创建taskHarvest 的实例并设置它的instance.quiet = true 时,它似乎并没有改变从Task 继承的值。如果我执行console.log(instance.quiet),它会返回true,但如果我到达Task 并执行console.log(this.quiet),它会返回false
  • 我没有问你它“应该”是什么。我问你实际上是什么。这里只有两种可能。其他东西正在将.quiet 设置回false,或者您稍后不再查看同一个对象。你必须弄清楚它是哪一个。您没有显示足够的代码让我们跟踪对象的生命周期以及可能发生的所有事情。例如,我不知道creep.assign() 做了什么。它可能正在复制对象,在其上设置一些属性等等......
  • 仅供参考,您可以添加一个用于调试目的的特殊属性,例如taskHarvest._test = "hello";,然后查看该属性是否仍然存在于step()console.log("_test:", this._test) 中,以查看您是否仍然拥有相同的对象。

标签: javascript class inheritance ecmascript-6 screeps


【解决方案1】:

没关系,这实际上不是继承问题;这是由游戏机制引起的问题:taskHarvest.quiet 没有在每次滴答时都被删除。 Screeps 只允许您将 JSON 可序列化对象存储在内存中,因此我将任务设置存储在内存中并在每个滴答声中重建任务对象:

Object.defineProperty(Creep.prototype, 'task', {
    get: function () { // provide new task object recreated from literals stored in creep.memory.task
        if (this.memory.task != null) {
            var task = tasks(this.memory.task.name);
            task.creepName = this.memory.task.creepName;
            task.targetID = this.memory.task.targetID;
            task.data = this.memory.task.data; // < task.quiet is now task.data.quiet
            return task;
        } else {
            return null;
        }
    },
    set: function(newTask) {
        if (newTask != null) {
            this.log("use Creep.assign() to assign tasks. Creep.task = ___ should only be used to null a task.");
        } else {
            this.memory.task = newTask;
        }
    }
});

taskHarvest.quiet 没有存储在内存中,因此它不会持续到任务的第一个滴答声之后。我现在将所有实例级可调整参数存储在task.data 对象中,所以task.quiet 现在是task.data.quiet。这解决了问题;很抱歉造成任何混乱!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-09
    • 2015-08-13
    • 2017-03-27
    • 1970-01-01
    • 2016-12-19
    • 2015-07-23
    • 1970-01-01
    相关资源
    最近更新 更多