i'm little bit confused with my code below, i am trying to access the subscribers attribute of a Category class and get undefined:
class Category {
constuctor(name){
this.name = name; // Category name
this.subscribers = [];
}
subcribe(observer){
console.log(this.subcribers)
this.subscribers.push(observer)// <----------- this is undefined ????
}
sale(disoucnt){
this.subscribers.forEach(observer => observer.notify(this.name, discount))
}
}
module.exports = Category;
// Observer
class Shopper {
notify(name, discount){ console.log(name, discount) }
}
module.exports = Shopper;
Form main file
const Category = require('./Category')
const Shopper = require('./Shopper')
const book = new Category("Book");
const shopper = new Shopper("PAUL")
const subscribe = book.subscribe(shopper);
// Output : TypeError: Cannot read property 'push' of undefined
Why this.subscribers is undefined ? thanks for your help
Thanks guys
The code is riddled with typos: constructor not constuctor, subscribe not subcribe, subscribers not subcribers, discount not disoucnt.
Because of the constructor typo your class was not even getting instantiated.
class Category {
constructor(name){
this.name = name; // Category name
this.subscribers = [];
}
subscribe(observer){
console.log(this.subscribers)
this.subscribers.push(observer)
console.log(this.subscribers)
}
sale(discount){
this.subscribers.forEach(observer => observer.notify(this.name, discount))
}
}
// module.exports = Category;
// Observer
class Shopper {
notify(name, discount){ console.log(name, discount) }
}
// module.exports = Shopper;
const book = new Category("Book");
const shopper = new Shopper("PAUL")
const subscribe = book.subscribe(shopper);
Related
I defined a class called Plan. Here is the code:
class Plan {
async getPlanText(ctx) {
return await this.getPlanDetails(ctx);
}
async getPlanDetails(ctx) {
return ...
}
}
exports.Plan = Plan;
I get:
this.getPlanDetails is not a function
What I did wrong?
I used the Plan class in this way:
const { Plan } = require('./controllers/plan.controller');
let planController = new Plan();
console.log(planController.getPlanText('my context'));
try this. Basically you need to bind the function to a class while passing so it knows where to get the dependencies from. You can read more here : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
const planController = new Plan();
const menu = new TelegraphInlineMenu(planController.getPlanText.bind(planController))
It seems that only if I fill out the child object directly in the Base function that is the only way that the getSettings function can see the this.name property correctly, but I was trying to have my objects in different files to avoid having one large file.
***child.js***
module.exports : {
getSettings: ()=>{
return this.name === 'foobar'
}
}
***base.js***
var Child = require('./child.js')
function Base(){
this.name = 'foobar'
this.child = Child
this.child2 = {}
for (var prop in Child){
this.child2[prop] = Child[prop]
}
this.child3 = {
getSettings: ()=>{
return this.name === 'foobar'
}
}
}
***index.js****
var Base = require('./base.js')
var b = new Base()
b.child.getSettings() //FAILS BECAUSE this.name is undefined
b.child2.getSettings() //FAILS BECAUSE this.name is undefined
b.child3.getSettings() //PASSES. this.name is defined
It's conventional in JS OOP to refer class instance as this, so it's semantically incorrect for child objects to refer to parent object as this. This also makes it difficult to work with an object like child that doesn't get desirable context as lexical this (like child3 does).
child object likely should be a class that are injected with parent instance as a dependency.
module.exports = class Child(parent) {
constructor(parent) {
this.parent = parent;
}
getSettings() {
return this.parent.name === 'foobar'
}
}
var Child = require('./child.js')
function Base(){
this.name = 'foobar'
this.child = new Child(this);
...
}
I am making a simple note taking app to learn node and ES6. I have 3 modules - App, NotesManager and Note. I am importing the Note class into the NotesManager and am trying to instantiate it in its addNote function. The problem is that even though the import is correct, it turns out to be undefined inside the class definition. A simpler solution would be to just instantiate the NotesManager class and add the Note class to its constructor however, I want to have NotesManager as a static utility class.
Here is my code.
Note.js
class Note {
constructor(title, body) {
this.title = title;
this.body = body;
}
}
module.exports = Note;
NotesManager.js
const note = require("./Note");
console.log("Note: ", note); //shows correctly
class NotesManager {
constructor() {}
static addNote(title, body) {
const note = new note(title, body); //Fails here as note is undefined
NotesManager.notes.push(note);
}
static getNote(title) {
if (title) {
console.log(`Getting Note: ${title}`);
} else {
console.log("Please provide a legit title");
}
}
static removeNote(title) {
if (title) {
console.log(`Removing Note: ${title}`);
} else {
console.log("Please provide a legit title");
}
}
static getAll() {
//console.log("Getting all notes ", NotesManager.notes, note);
}
}
NotesManager.notes = []; //Want notes to be a static variable
module.exports.NotesManager = NotesManager;
App.js
console.log("Starting App");
const fs = require("fs"),
_ = require("lodash"),
yargs = require("yargs"),
{ NotesManager } = require("./NotesManager");
console.log(NotesManager.getAll()); //works
const command = process.argv[2],
argv = yargs.argv;
console.log(argv);
switch (command) {
case "add":
const title = argv.title || "No title given";
const body = argv.body || "";
NotesManager.addNote(title, body); //Fails here
break;
case "list":
NotesManager.getAll();
break;
case "remove":
NotesManager.removeNote(argv.title);
break;
case "read":
NotesManager.getNote(argv.title);
break;
default:
notes.getAll();
break;
}
Is it possible for me to create a strict utility class which I can use without instantiating like in Java? Pretty new here and have tried searching for it without any luck. Thank you for your help.
When you do this:
const note = new note(title, body);
you redefine note shadowing the original note from the outer scope. You need to pick a different variable name.
Something like this should work better:
static addNote(title, body) {
const some_note = new note(title, body); //Fails here as note is undefined
NotesManager.notes.push(some_note);
}
I defined a object A in which i need to store some objects.
How can i assign the query result to the property of the object.
Here is my example code.
function A(Job){
this.job = Job;
this.location ={};
models.locations.findOne({
where:{
job_id:this.job.id
}
}).then(function(location){
//what should i do here to store it in A.locaiton
}
}
Hold the reference of this into a that property (or any other name you prefer) and then use that.location. For example:
function A(Job) {
var that = this;
that.job = Job;
that.location = {};
models.locations.findOne({
where: {
job_id: this.job.id
}
}).then(function (location) {
that.location = location;
});
}
Hope this helps.
I have spotted buggy behavior in javascript es6 inheritance using Singleton pattern.
Code is:
let instanceOne = null;
class One {
constructor() {
if (instanceOne) return instanceOne;
this.name = 'one';
instanceOne = this;
return instanceOne;
}
method() {
console.log('Method in one');
}
}
let instanceTwo = null;
class Two extends One {
constructor() {
super();
if (instanceTwo) return instanceTwo;
this.name = 'two';
instanceTwo = this;
return instanceTwo;
}
method() {
console.log('Method in two');
}
}
const objOne = new One();
const objTwo = new Two();
console.log(objOne.name);
console.log(objTwo.name);
objOne.method();
objTwo.method();
Display is:
two
two
Method in one
Method in one
The inheritance get fucked up somehow. Here the attributes get overridden but not the object methods.
My question is why is it working (like now throw) and can you explain this behavior?
It appears that new objects need brand new object as parent (see solution below).
If you encounter the same problem, here is my solution:
let instanceOne = null;
class One {
constructor(brandNewInstance = false) {
if (instanceOne && !brandNewInstance) return instanceOne;
this.name = 'one';
if (brandNewInstance) return this;
instanceOne = this;
return instanceOne;
}
method() {
console.log('Method in one');
}
}
let instanceTwo = null;
class Two extends One {
constructor() {
super(true);
if (instanceTwo) return instanceTwo;
this.name = 'two';
instanceTwo = this;
return instanceTwo;
}
method() {
console.log('Method in two');
}
}
I use node.js v6.9.1
This happens because of this line:
if (instanceOne) return instanceOne;
One constructor runs twice in the code above. Second One call is super(), in this case this is created from Two.prototype, and object method is Two.prototype.method.
Return statement from super() substitutes this with One singleton, and then Two constructor just modifies One singleton instance.
Static property can be used instead to hold instances:
constructor() {
if (this.constructor.hasOwnProperty('instance'))
return this.constructor.instance;
this.constructor.instance = this;
this.name = 'one';
}
Or if sharing an instance with descendant classes is the expected behaviour,
constructor() {
if ('instance' in this.constructor)
return this.constructor.instance;
this.name = 'one';
this.constructor.instance = this;
}
In this case all singleton mechanics is done by One constructor, Two just needs to call super:
constructor() {
super();
this.name = 'two';
}
Also, ending return statement is redundant. this doesn't have to be returned explicitly.
You are doing something a bit strange. Constructors and subclasses in ecmascript 6 do not work in the way you think they do. You may wish to read this blog post (particularly section 4) to learn more.
Taking from that article, your code looks like this under the hood:
let instanceOne = null;
function One() {
// var this = Object.create(new.target.prototype); // under the hood
if (instanceOne) return instanceOne;
this.name = 'one';
instanceOne = this;
return instanceOne;
}
One.prototype.method = function() { console.log('Method in one'); }
let instanceTwo = null;
function Two() {
var that = undefined;
that = Reflect.construct(One, [], new.target);
if (instanceTwo) return instanceTwo;
that.name = 'two';
instanceTwo = that;
return instanceTwo;
}
Two.prototype.method = function() { console.log('Method in two'); }
Object.setPrototypeOf(Two, One);
Object.setPrototypeOf(Two.prototype, One.prototype);
const objOne = Reflect.construct(One, [], One);
const objTwo = Reflect.construct(Two, [], Two);
console.log(objOne.name);
console.log(objTwo.name);
objOne.method();
objTwo.method();
(new.target is the value passed as the third argument of Reflect.construct)
You can see that for the Two class, no new object is being created and Two.prototype is not used. Instead, the One singleton instance is used and mutated.