Modifying variables in subclass instances - javascript

I've become hopelessly addicted to Screeps recently, and I refactored some code to make a task-based implementation. Tasks are things like "walk to and then harvest until you are at full capacity" and are based off of a single base task template written as an ES6-style class. Creeps can be assigned tasks through a wrapper (tasks.js) that loads the relevant task file and returns a new task instance.
Today I ran into a strange bug that makes me think I don't fully understand Javascript's inheritance model. Below is the relevant code:
Task.js: (base task class)
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: (harvesting task)
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: (wrapper to generate a new task instance via a function call)
module.exports = function (taskName) {
var TaskClass = require('task_' + taskName); // all tasks follow this naming pattern
var taskInstance = new TaskClass;
return taskInstance;
};
harvester.js: (behavior model for a harvester creep)
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();
},
...
}
When I assign a creep to harvest from a source, I create a new task from task_harvest.js, set its quiet property to be true, and bind it and its target to the creep. Once the creep has a task it is instructed to run it until it becomes invalid (code not included above). The creep executes the task fine, but it still logs everything to the console.
I would think that in harvester.js, when I set taskHarvest.quiet = true;, the behavior imported from Task.js would see this.quiet as true. However, it seems as though that is not the case. In roleHarvester, running console.log(creep.task.quiet) returns true, but in Task, running console.log(this.quiet) when the creep is executing the assigned task gives false.
I could add quiet into the constructor as an optional parameter, but that's convoluted and I want to know why what I'm doing isn't working.

Nevermind, it actually wasn't an inheritance problem; it was a problem caused by the game mechanics: taskHarvest.quiet wasn't getting deleted each tick. Screeps only allows you to store JSON-serializable objects in memory, so I store the task settings in memory and reconstruct the task object each tick:
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 wasn't getting stored in memory, so it wouldn't persist past the first tick of the task. I now store all instance-level adjustable parameters in a task.data object, so task.quiet is now task.data.quiet. This fixed the problem; sorry for producing any confusion!

Related

What is the difference between these two singleton approaches in JS?

The way to solve the singleton pattern in JS (TS actually) is looks like this (the best approach if you ask me):
export default class Singleton {
private static _instance: Selection
constructor() {
if (Selection._instance) {
return Singleton._instance
} else {
Singleton._instance = this
}
}
}
And then:
import Singleton from './Singleton.ts'
const singleton_1 = new Singleton()
const singleton_2 = new Singleton()
singleton_1 === singleton_2 // true
But in this scenario I have to create new variables every time I need that class.
I can achieve exactly the same the easier way:
class Singleton {
constructor() {
// some logic
}
}
export default new Singleton()
import Singleton from './Singleton.ts'
const wut = Singleton.field
Singleton.method('do something')
Am I getting something wrong or the first approach is a little bit excessive and complicated and the second one just do the same thing in more obvious way?
I understand that if I have static fields in my class, I couldn't use it that way, but cases when you really need static fields are rare.
It is essential in a scenario where only one instance needs to be created, for example, a database connection. It is only possible to create an instance when the connection is closed or you make sure to close the open instance before opening a new one. This pattern is also referred to as strict pattern, one drawback associated with this pattern is its daunting experience in testing because of its hidden dependencies objects which are not easily singled out for testing.
let databaseInstance = null;
// tracks the number of instances created at a certain time
let count = 0;
function init() {
console.log(`Opening database #${count + 1}`);
//now perform operation
}
function createIntance() {
if(databaseInstance == null) {
databaseInstance = init();
}
return databaseInstance;
}
function closeIntance() {
console.log('closing database');
databaseInstance = null;
}
return {
open: createIntance,
close: closeIntance
}
}
const database = DatabseConnection();
database.open(); //Open database #1
database.open(); //Open database #1
database.open(); //Open database #1
database.close(); //close database
source: https://codesource.io/javascript-design-patterns/

Assigning callback events from an array of strings (PIXI.js)

all. I have kind of a doozy of a problem, that could be solved really simply, if I just wanted to duplicate the code. I mean, really, it's a small part of a project that I'm doing just to see if I can, more than anything else, but it is bothering me since I've thought it up.
The Project
For fun, I've decided to take someone's ActionScript 3, text-based game engine and convert it to TypeScript and ultimately JavaScript using PixiJS.
The thing is, there are still 20213 errors to be fixed running tsc, so I could just leave this to a later date. But I was working on the Button class, which they defined as a subclass of MovieClip. That's fine; I just responded by reading up on PIXI buttons, and they seem fairly straightforward. Just, in the button's constructor, add something akin to the following lines:
export class Button extends PIXI.Sprite {
private _callback : Function;
private _height : number;
private _width : number;
public get callback() : Function { return this._callback; }
public set callback(fn : Function) {this._callback = fn; }
public get height() : number { return this._height; }
public set height(h : number) {this._height = h; }
public get width() : number {return this._width; }
public set width(w : number) {this._width = w; }
public constructor(width = 180, height = 90, callback: Function = null){
super(new PIXI.Texture(new PIXI.BaseTexture(GLOBAL.BTN_BACK, PIXI.SCALE_MODES.NEAREST)));
this.callback = callback;
this.width = width;
this.height = height;
this.buttonMode = true;
this.interactive = true;
this.anchor.set(0.5);
this.on('mousedown', this.callback)
.on('touchstart', this.callback);
}
}
That's a bit of a simplified version, and the version I did on Codepen uses a Container and a private _sprite field instead (as well as a ColorMatrixFilter that doesn't work too well on the black icons I picked out, but that's not really important for this question), but that's roughly the gist of how it's done.
The Problem
The problem is that, in the codepen, I'd like to do the following:
// assign `this.callback` to each of the following events:
let that = this;
['click','mousedown','touchstart'].map(evt => that.on(evt, that.callback});
with a simple call being passed in their constructors elsewhere:
for (let n = 0; n < 5; ++n){
btnArray.push(new Button(16, 16, () => console.info('You pushed button %d', n)));
}
but I'm not getting anything from them, even in the Chrome Console. I even logged that ColorMatrixFilter I mentioned earlier, to see if it was console.info that was wrong. Nope. So now, I'm confused on that. I was hoping to be able to just make a GLOBAL (a legacy static object from the AS source) key to iterate through for the events, but it looks like that's not happening.
The Questions
Is what I'm trying to do feasible, if odd? Is it blocked by a security feature (for which I'd be grateful)? If not, what am I doing wrong?
Should I even worry about setting all these different event handlers, or is just listening to click enough?
When an arrow function like your event map is executed the this context is not set, so any code that references this is going to get the current value, including any functions your map calls.
Replace your event map with the following:
['click','mousedown','touchstart'].map(function(evt) { that.on(evt, that.callback} } );
A demonstration:
function Named(x) {
this.name = x;
}
var foo = new Named("foo");
var bar = new Named("bar");
var showFunc = function show() {
// this is context dependant
console.log(this.name);
}
var showArrow;
// this is the window
showArrow = () => console.log(this.name);
var fooShowArrow;
(function() {
// this is foo
that = this;
fooShowArrow = () => console.log(that.name);
}).apply(foo);
var example = function(func) {
// For the demo, at this point, this will always be bar
func.apply(this, [ "arbitrary value" ]);
}
// explicitly set the current "this" to bar for the execution of these functions
example.apply(bar, [showFunc]); // works
example.apply(bar, [showArrow]); // fails, this is still the window
example.apply(bar, [fooShowArrow]); // fails, this is still foo

How to show percent done in terminal

Good day all.
Today i'm working in this complex script that makes request's to a site with server-side rendering, get's the HTML, breaks and grabs some data. The script has 4 phases: phaseOne, phaseTwo, phaseThree and phaseFour.
Which phases has a similar interface:
class PhaseOne {
constructor(MAP) {
this.MAP = MAP || MAP;
}
// All code related with the phase here.
process() {}
}
So i'm working upon this MAP object in all phases, and i'm calling each phase in a stack, like this:
let phases = require('./phases');
[
// 'Initial',
'PhaseOne',
'PhaseTwo',
'PhaseThree',
'PhaseFour',
].reduce((m, fn) => {
return new phases[fn](m).process();
}, MAP);
Everything is working fine. My problem is: Some phases are REALLY slow.. all the program will take 30 minutes to finish.. and i would like to see in my terminal the percentage of each phase.
Like:
PhaseOne: 10%
PhaseOne: 11%
PhaseOne: 12%
But i don't have any idea and i can't find a good tutorial to do that..
Currently inside my process functions i have for loops, if statements.. in general i'm using imperative style..
An example of PhaseOne:
// In this phase we need the property string in MAP.aguia01 to
// assign the first context and extract the data with regex.
if (typeof this.MAP.aguia01.string === 'undefined') {
cli.fatal(
'MAP doesn\'t have the necessary properties to run in Aguia01 phase. Exiting...'
);
}
for (let month of months) {
this.MAP.aguia01.string += requests.aguia01.apply(this, [month]);
}
for (let info of patterns.aguia01.infos) {
this.MAP.aguia01.infos[info.name] = (
this.MAP.aguia01.string.match(info.pattern)
)[1];
}
for (let line of patterns.aguia01.lines) {
this.MAP.aguia01.lines[line.name] = (
this.MAP.aguia01.string.match(line.pattern)
)[1];
}
So.. Is it possible to do what i want with imperative style?
Thanks.
There is the progress package but it's only up to you how you define "progress". You define a number of ticks corresponding to the completed state and then, you just call a method on the progress bar to make it "progress". An example:
var ProgressBar = require('progress');
// 10 ticks to complete the task
var bar = new ProgressBar(':bar', { total: 10 });
var timer = setInterval(function () {
// make the bar tick(), each call will make a 10% progress
bar.tick();
if (bar.complete) {
console.log('\ncomplete\n');
clearInterval(timer);
}
}, 100);
How about keeping a context object for progress outside of your reduce call? You could make it an event emitter, and then pass it in to your process function. Inside your process function you could emit progress events, which could then be logged. Perhaps something like this:
let phases = require('./phases');
//set up
let progressMonitor = new require('events')
progressMonitor.on('progress', percentDone => {
console.log(percentDone + '% done')
})
// your existing code
[
// 'Initial',
'PhaseOne',
'PhaseTwo',
'PhaseThree',
'PhaseFour',
].reduce((m, fn) => {
return new phases[fn](m).process(progressMonitor);
}, MAP);
and then inside your process functions:
class PhaseOne {
constructor(MAP) {
this.MAP = MAP || MAP;
}
// All code related with the phase here.
process(progressMonitor) {
//do work
progressMonitor.emit('progress', 10)
//more work
progressMonitor.emit('progress', 15)
//much work
progressMonitor.emit('progress', 75)
}
}

Accessing an object's parent

Ok, first up I know an object has no reference to it's container unless explicitly defined, so I am looking for a work around here.
Take the following code (heavily simplified from my use case for readability):
var cid = 0;
var Command = function(c) {
this.id = cid += 1;
this.transient = false;
return this;
}
var sid = 0;
var CommandSet = function() {
this.id = sid += 1;
this.commands = [];
this.transients = 0;
return this;
}
CommandSet.prototype.parent = null;
CommandSet.prototype.recurse = function(callback) {
callback.call(this);
if (this.parent instanceof CommandSet) {
this.parent.recurse(callback);
}
}
CommandSet.prototype.createSubset = function() {
var set = new CommandSet();
set.parent = this;
set.commands = this.commands;
set.transients = this.transients;
return set;
}
CommandSet.prototype.addCommand = function(c) {
if (c instanceof Command) {
this.commands.push(c);
if (c.transient) {
this.recurse(function() {
this.transients++;
});
}
}
return this;
}
CommandSet.prototype.toggleTransient = function(c) {
if (c instanceof Command) {
c.transient = true;
this.recurse(function() {
this.transients++;
});
}
return this;
}
If I then do the following (http://jsfiddle.net/5KGd8/1/):
var s1 = new CommandSet();
var c1 = new Command();
var c2 = new Command();
s1.addCommand(c1).addCommand(c2);
var s2 = s1.createSubset();
var s3 = s1.createSubset();
s2.toggleTransient(c1);
console.log(s1);
console.log(s2);
console.log(s3);
s1 now has 1 transient, s2 now has 1 transient but s3 still has none despite containing a reference to the same Command objects.
Possible solutions:
I could build a reference into each command which stores all the
sets it is located inside and iterate through those, however this is
going to cause some serious memory issues as the real nature of my
application requires that subsets can be garbage collected (The user
will create a lot of them anonymously often without realising) and this will retain a
reference to them after they have been used. The parent reference is fine as I want the parent set to exist as long as it has a surviving subset.
I could explicitly force the user to run a delete function on a
subset when it is no longer needed which would remove all internal references to it but this complicates things for
them and I like things to work automagically. The nature of my application means I would like the user to create subsets at times where they may not even realise they have done so (Through other functions which create and perform on subsets).
Can anyone think of a way to solve this problem without the issues described in my two solutions?
Sorry, this is not an answer but want to make sure I understand the problem.
A CommandSet can have Commands, when you change a Command's transient property you would like the CommandSet(s) that contain that Command to have an updated counter of transient the Commands it contains.
If the story ends here you could simply have Command maintain a list of CommandSet that the Command is in and update it's containers.
This would not work however because you would have CommandSets created in a function and when these go out of scope they won't be garbage collected because the Command(s) they contain would hold a reference to them. These commands would not go out of scope with the CommandSets because they are also contained in other (global) CommandSets.
Re assigning a primitive type (transients) does not re assign that in the subset or main set, but what if transients was not a primitive?
In the constructor:
this.transients = {count:0};
In createSubset
set.transients = this.transients
In the toggleTransient
this.transients.count++; or --
No matter if you fiddle with transients in subset or main set, as long as you use the toggleTransient it'll change count for all.

Are Interfaces in JavaScript necessary?

I suppose this could apply to any dynamic language, but the one I'm using is JavaScript. We have a situation where we're writing a couple of controls in JavaScript that need to expose a Send() function which is then called by the page that hosts the JavaScript. We have an array of objects that have this Send function defined so we iterate through the collection and call Send() on each of the objects.
In an OO language, if you wanted to do something similar, you'd have an IControl interface that has a Send() function that must be implemented by each control and then you'd have a collection of IControl implementations that you'd iterate through and call the send method on.
My question is, with JavaScript being a dynamic language, is there any need to define an interface that the controls should inherit from, or is it good enough to just call the Send() function exposed on the controls?
Dynamic languages often encourage Duck Typing, in which methods of the object dictate how it should be used rather than an explicit contract (such as an interface).
This is the same for PHP; you don't really need interfaces. But they exist for architectural needs. In PHP, you can specify type hints for functions which can be useful.
Second, an interface is a contract. It's a formal contract that all objects from this interface have those functions. Better to ensure that your classes meet those requirements than to remember: "mm, this class has isEnabled() but the other one is checkIfEnabled()". Interfaces help you to standardise. Others working on the derived object don't have to check whether the name is isEnabled or checkIfEnabled (better to let the interpreter catch those problems).
Since you can call any method on any object in a dynamic language, I'm not sure how interfaces would come into play in any truly useful way. There are no contracts to enforce because everything is determined at invocation time - an object could even change whether it conforms to a "contract" through its life as methods are added and removed throughout runtime. The call will fail if the object doesn't fulfill a contract or it will fail if it doesn't implement a member - either case is the same for most practical purposes.
We saw a nice implementation in the page below, this is ours (short version of it)
var Interface = function (methods) {
var self = this;
self.methods = [];
for (var i = 0, len = methods.length; i < len; i++) {
self.methods.push(methods[i]);
}
this.implementedBy = function (object) {
for (var j = 0, methodsLen = self.methods.length; j < methodsLen; j++) {
var method = self.methods[j];
if (!object[method] || typeof object[method] !== 'function') {
return false;
}
}
return true;
}
};
//Call
var IWorkflow = new Interface(['start', 'getSteps', 'end']);
if (IWorkflow.implementedBy(currentWorkFlow)) {
currentWorkFlow.start(model);
}
The whole example is at:
http://www.javascriptbank.com/how-implement-interfaces-in-javascript.html
Another alternative to the interfaces is offered by bob.js:
1. Check if the interface is implemented:
var iFace = { say: function () { }, write: function () { } };
var obj1 = { say: function() { }, write: function () { }, read: function () { } };
var obj2 = { say: function () { }, read: function () { } };
console.log('1: ' + bob.obj.canExtractInterface(obj1, iFace));
console.log('2: ' + bob.obj.canExtractInterface(obj2, iFace));
// Output:
// 1: true
// 2: false
2. Extract interface from the object and still execute the functions properly:
var obj = {
msgCount: 0,
say: function (msg) { console.log(++this.msgCount + ': ' + msg); },
sum: function (a, b) { console.log(a + b); }
};
var iFace = { say: function () { } };
obj = bob.obj.extractInterface(obj, iFace);
obj.say('Hello!');
obj.say('How is your day?');
obj.say('Good bye!');
// Output:
// 1: Hello!
// 2: How is your day?
// 3: Good bye!

Categories