Adding properties dynamically to node module - javascript

I am experimenting with different ways to code a Node.js module and tried this:
game.js
var board = require('./board'),
player = require('./player');
// setting module.exports to a function constructor so I can make instances of this node module from my test
var game = module.exports = function(){};
// dynamically add properties and set their default values
// I don't think I need to use any prototypes here right?
// And yes I realize I could use ES6 classes with an explicit constructor but that's a suggestion we can put on the side for now...
game.initialize = function(){
game.started = false;
game.status = 'not started';
game.board = board.create();
return game;
};
game.start = function(){
game.started = true
};
game-test.js
let chai = require('chai'),
should = chai.should(),
game = require('../src/game');
describe('Game - Initial State', () => {
var newGame;
beforeEach((done) => {
newGame = new game().initialize;
done();
});
it('should contain a new board to play on', () => {
should.exist(newGame.board);
});
...
I'm getting the error "Cannot read property 'board' of undefined"
If I remove the .initialize() I get an instance of game but then no properties. I'm not sure if this is even a good pattern but first would like to know what I'm doing wrong here. And then any additional suggestions I'm open to hearing.

Game.initialize is a function.
In your test your are not calling the function, so your variable newGame is just a ref to Game.initialize instead of a Game instance
// your line
newGame = new game().initialize;
// should be
newGame = new game().initialize();
Edit: Also, you may want to use this instead of game in your initialize() function.

Related

Why can’t I access a property on “this” in a class via its prototype?

I wrote this class and have set up an array property for it. Then, I want to add an item to this array.
However, when I try to do it, I get the error “Uncaught TypeError: Cannot read property push of undefined”.
Isn’t this possible?
class test {
constructor() {
this.myArray = [];
}
myMethod() {
this.myArray.push("ok");
}
};
console.log(test.prototype.myMethod());
That’s not how classes are used. You need to instantiate test first, by using new test(). The constructor was never called in your case, so this.myArray was never defined.
This is the only way this can work:
let testInstance = new test();
testInstance.myMethod();
This way, the constructor is called and there will be no error.
Of course, next you’ll need some way of retrieving your array, in order to see the effect.
try to create the instance first. See the code I've commented it in details
test.prototype = {
constructor: test,
myMethod: function() {
this.myArray.push("ok");
}
};
var test = function(){
this.myArray = [];
}
test.prototype = { // add our custom constructor and custom methods
constructor: test,
myMethod: function() {
this.myArray.push("ok");
}
};
var myVar = new test(); // create new instance of test
myVar.myMethod(); // run custom method to push val
console.log( myVar.myArray );
You need to initiate your class test first.
var t = new test();
For your information:
console.log(test.prototype.myMethod());
will give you "undefined". Try e.g. :
var t = new test();
t.myMethod();
console.log(t.myArray);
to get output similar to this:
Array [ "ok" ]

Integrate EventEmitter in Object construtor to use in prototype methods

I have the following, strange problem:
I wrote a "Class" Game. This Class has a constructor and one prototype method. I want the whole construct to be an EventEmitter. So I thought I could just inherit the event.EventEmitter for my constructor.
It looked first as follows:
game.js
var EventEmitter = require('events').EventEmitter;
var util = require('util');
/*
Game factory
*/
function Game(catalogue, speed) {
//EventEmitter.call(this);
this.catalogue = catalogue || null;
this.speed = speed || 10;
}
Game.prototype.listen = function(){
var self = this;
setInterval(function(){
self.emit('init', 0);
}, 500);
}
util.inherits(Game, EventEmitter);
module.exports = Game;
I use socket.io to connect to the client. In my main socket routine I use the following code to start a new game (instantiate)
controller.js
socket.on('startGame', function(){
var myGame = new Game('default', 10);
myGame.init();
myGame.on('init', function(status){
console.log('Did start with status code: ', status);
});
};
This does not work as expected.Error is:
Missing error handler on `socket`.
TypeError: undefined is not a function
at Socket.<anonymous>
When I use the emit event in the constructor, it works (without myGame.listen() in the console.js, of course):
function Game(catalogue, speed) {
//EventEmitter.call(this);
this.catalogue = catalogue || null;
this.speed = speed || 10;
var self = this;
setInterval(function(){
self.emit('init', (Math.random()*10).toFixed(0));
}, 500)
}
So what is wrong here?
Note that I don't need
EventEmitter.call(this);
in the constructor in the second example.
But independent from commenting this out or leaving it in, this downs change anything.
Why do I need this at all? Do I?
Maybe you can help. Kind regard.
Martin
You have to move your util.inherits(Game, EventEmitter); to before you start adding functions to your prototype. The util.inherits() meddles with the prototype, so anything placed on it before then is lost.
Additionally, when you inherit from another object (like EventEmitter), you really should call the parent constructor (EventEmitter.call(this)) because it may need to do some initialization of its own.
Updated example with Node.js v11.12.0
const EventEmitter = require('events');
module.exports = class Game extends EventEmitter {
constructor(catalogue, speed) {
super();
this.catalogue = catalogue || null;
this.speed = speed || 10;
}
listen() {
setInterval(() => {
self.emit('init', 0);
}, 500);
}
};
let myGame = new Game('default', 10);
myGame.listen();
myGame.on('init', status => {
console.log('Did start with status code: ', status);
});
Some neat new stuff here.
Don't need require('events').EventEmitter suffix part anymore. It is still available for backwards compatibility.
Can use class and extends.
Can use arrow functions in the setInterval which implicitly binds to this instead of needing to map this to self.

I am getting: Cannot call method 'someMethodName' of undefined when trying to access an object in a javascript clas

I am almost new to JavaScript, and I am trying to access an object within a class. This is my class definition in a file called analysis.po.js:
var AnalysisPage = function () {
(some code here)
this.getSpousesCreditBureau = function() {
return {
pdScore: getSpousesCreditBureauElement('pdScore'),
qualification: getSpousesCreditBureauElement('qualification'),
estimatedFee: getSpousesCreditBureauElement('estimatedFee'),
currentDebt: getSpousesCreditBureauElement('currentDebt'),
maxDebt: getSpousesCreditBureauElement('maxDebt'),
arrears: getSpousesCreditBureauElement('arrears'),
segment: getSpousesCreditBureauElement('segment'),
bpGlobalRisk: getSpousesCreditBureauElement('bpGlobalRisk'),
groupGlobalRisk: getSpousesCreditBureauElement('groupGlobalRisk')
};
};
(some other code here)
};
module.exports = new AnalysisPage();
This is the piece of code where I try to get the object getSpousesCreditBerauElement in another file called analysis.spec.js:
var App = require('../app.po.js'),
Util = require('../util.js'),
AnalysisPage = require('./analysis.po.js'),
AnalysisData = require('./analysis.data.js');
(some code here)
var analysis = new AnalysisPage();
Util.verifyElementsAreDisplayed(analysis.getSpousesCreditBureau());
(some other code here)
The error I am getting is:
Cannot call method 'getSpousesCreditBureau' of undefined
You're not actually exporting AnalysisPage and you're not calling it correctly.
Export the class with:
module.exports = AnalysisPage;
In comparison
module.exports = new AnalysisPage();
Exports an instance of the class.
The right way to call it is then:
var instance = new AnalysisPage();
Util.verifyElementsAreDisplayed(instance.getSpousesCreditBureau());
(Original question has been modified, code was:)
var analysis = new AnalysisPage();
Util.verifyElementsAreDisplayed(AnalysisPage.getSpousesCreditBureau());
You can export just the instance, in that case call it like:
var instance = require('./analysis.po.js');
Util.verifyElementsAreDisplayed(instance.getSpousesCreditBureau());
So no new anywhere.
Did you tried:
var analysis = new AnalysisPage();
Util.verifyElementsAreDisplayed(analysis.getSpousesCreditBureau());
When you access the method like this AnalysisPage.getSpousesCreditBureau() you are not accessing the instance, but the class definition.

EventEmitter has no emit

i have this node js script:
var EventEmitter = require('events').EventEmitter,
util = require('util');
var pfioObject = function () {
this.init = function () {
console.log("started server");
};
this.deinit = function () {
console.log("stopped server");
};
this.read_input = function () {
return 0;
};
};
console.log(util.inspect(EventEmitter, false, null)); //<--- this shows no method emit either
var pfio = new pfioObject();
var pfioServer = function () {
this.prev_state = 0;
this.start = function () {
pfio.init();
this.watchInputs();
};
this.stop = function () {
pfio.deinit();
};
}
util.inherits(pfioServer, EventEmitter);
// add some event emitting methods to it
pfioServer.prototype.watchInputs = function () {
var state = pfio.read_input();
if (state !== this.prev_state) {
this.emit('pfio.inputs.changed', state, this.prev_state);
this.prev_state = state;
}
setTimeout(this.watchInputs, 10); // going to put this on the event loop next event, more efficient
};
// export the object as a module
module.exports = new pfioServer();
For some reason the node error says that there is no such object as emit, i have done npm install events to see if that will fix it, it didn't. I'm unsure as to why I'm getting this error.
I think somewhere along my code there is an error but I can't see anything.
To run this code I have another script which does this:
var pfioServer = require('./pfioServer'),
util = require('util');
console.log(util.inspect(pfioServer, false, null)); //<--- this line shows the pfioServer with out the prototype function watchInputs
pfioServer.start();
EDIT
I think I may have missed out on some vital bits of code around the event emitter stuff, am looking into instantiation of the event emitter class
Slight Change
So instead of EventEmitter being inherited, i instantiated it by doing var emitter = new EventEmitter()
Then after that I got errors in the util.inspect about the object having to be an object or be null.
No success yet.
I found two things that had to be changed for the first code-block to run without errors:
Explicitly instantiate events.EventEmitter():
var events = require('events'); var EventEmitter = new events.EventEmitter();
Change the call to util.inherits:
util.inherits(pfioServer, events.EventEmitter);
The last thing to make the server run is what robertklep wrote: fix binding in setTimeout()
setTimeout(this.watchInputs.bind(this), 10);
The reason is this line:
setTimeout(this.watchInputs, 10);
When the timeout is triggered and this.watchInputs is called, it has lost its context.
You need to explicitly set the context object (in other words, what this inside the method should point to) for that call by using bind:
setTimeout(this.watchInputs.bind(this), 10);
console.log(util.inspect(EventEmitter, false, null));
// this shows no method emit either
The EventEmitter constructor function does not have such a method. EventEmitter.prototype has. To print the (non-enumerable) .prototype property, you can use util.inspect(EventEmitter, {showHidden: true}) as #Emissary mentioned in the comments.
// this line shows the pfioServer with out the prototype function watchInputs
console.log(util.inspect(pfioServer, false, null));
Yes. util.inspect does not show inherited properties, only those apparent on the pfioServer instance itself.
setTimeout(this.watchInputs, 10);
// going to put this on the event loop next event, more efficient
I'd rather say it prevents an infinite loop… However, this also destroys the this context in the next invokation, which is no more your pfioServer instance. See How to access the correct `this` context inside a callback?
In your case however, I don't see the necessity of using a constructor and inheriting from a prototype anyway. You're just exporting a singleton object, which you simply could instantiate with an object literal and reference by its variable name.

Collection/Instance objects style vie javascript without proto

I'm trying to make classical Collection/Instance model via javascript. So Collection object has some method for working with full collection and ((new Collection()) instanceof Instance) has methods to work with the instance. My code is rather simple.
var Collection = function Collection() {
this.message = "collection";
var I = Instance.bind(null, this);
I.__proto__ = this;
return I;
};
Collection.prototype = {
collectionMethod: function () {
console.log(this.message);
}
};
var Instance = function Instance(collection) {
this.collection = collection;
this.message = "instance";
};
Instance.prototype = {
instanceMethod: function () {
console.log(this.message);
}
};
// Test exec (values are like expected);
var C = new Collection();
var i = new C();
C.collectionMethod(); // collection
i.instanceMethod(); // instance
i.collection.collectionMethod(); // collection
C.newMethod(); // TypeError
i.newMethod(); // TypeError
Collection.prototype.newMethod = Instance.prototype.newMethod = function () {
console.log("newMethod: " + this.message);
}
C.newMethod(); // newMethod: collection
i.newMethod(); // newMethod: instance
But i don't want to use proto because it's not a part of standart and doesn't work in IE at all. Is there any way around in this case?
Some explanations about what's all about. For example you have a collection of users. And you want to be able find the user and create new one.
So you create new collection like
var User = new Collection();
Then you create new instance like.
var me = new User({name: "alex"});
And now you find this instance like
User.find_by_name("alex"); // === me
Also (in fact this is the main reason i'm doing this way instead of just creating something like User.new function to use it like var me = User.new({name: "alex"});) you can know who I am doing something like (if you for example have also var Dog = new Collection())
me instanceof Dog // false
me instanceof User // true
This code:
var I = Instance.bind(null, this);
I.__proto__ = this;
return I;
really doesn't make much sense. Function.bind creates a new function, so anyone calling your Collection function, in any way, will get back a function, not an object whose prototype is set to the function's prototype.
In general, if you want to create an object whose prototype is set to a specific object, you don't set __proto__ since that's not standard, as you stated. The best way is to just use Object.create (which is shimable if you want to support IE8).
var I = Object.create(this);
Also, the reason you're getting errors on newMethod is because you're trying to call them before you add them to the prototype:
Collection.prototype.newMethod = Instance.prototype.newMethod = function () {
console.log("newMethod: " + this.message);
}
C.newMethod(); // should work now
i.newMethod(); // should work now
So seems like it's impossible for now. More information can be found here.
How do I inherit javascript functions ?

Categories

Resources