Recursive prototype inheritance in nodejs / javascript
In my nodejs program, I have a module called human and it has a prototype object (about) which also has its child method (describe). I am trying to access objects, but I am getting undefined.
Can someone please correct my understanding? what am I doing wrong here?
index.js
var Person = require("./person");
var sam = new Person({name:"Sam",age:23})
sam.about.describe();
person.js
module.exports = (function() {
var person = function(options) {
if (options && options.name) this.name = options.name;
if (options && options.age) this.age = options.age;
}
person.prototype.about = {
describe : function(){
console.log("I am",this.name,"and",this.age,"years old");
}
}
return person;
})();
Expected result: "I am Sam and 23 years old" Actual result: "I am undefined and undefined years old"
source to share
As others have said, this
your example refers to an object, not a person instance.
One way to get the API you want is to create that namespace about
inside the constructor and use it bind
to set the correct context for the handler describe
.
module.exports = (function() {
var person = function(options) {
if (options && options.name) this.name = options.name;
if (options && options.age) this.age = options.age;
this.about = {
describe: function () {
console.log("I am",this.name,"and",this.age,"years old");
}.bind(this)
};
}
return person;
})();
This way you can simply call
var Person = require("./person");
var sam = new Person({name:"Sam",age:23})
sam.about.describe();
>>> I am Sam and 23 years old
source to share
This is because it this
refers to the direct parent describe
, which about
:
person.prototype.about = {
describe : function() {
console.log("I am",this.name,"and",this.age,"years old");
}
}
You will need a weak reference to the main object Person
passed to the namespace about
, for example, and use that instead this
. But I don’t like it, it’s cut off, feels wrong and looks smelly.
Instead, let's just see that it adds a completely new package of functionality to the Person object and allows it to be made a helper:
module.exports = (function() {
var PersonHelper = function(person) {
this.person = person;
describePerson: function() {
console.log("I am",this.person.name,"and",this.person.age,"years old");
}
/* more methods */
}
return PersonHelper;
})();
So, you could do:
module.exports = (function() {
var person = function(options) {
if (options && options.name) this.name = options.name;
if (options && options.age) this.age = options.age;
}
return person;
})();
var Person = require("./person");
var PersonHelper = require("./personHelper");
var sam = new Person({name:"Sam",age:23})
var helper = new PersonHelper(person);
helper.describePerson();
source to share
If you really want to use sam.about.describe
using about
", then one approach is
Object.defineProperty(person.prototype, 'about', {
get() {
return {
describe: () => console.log("I am", this.name, "and", this.age, "years old");
};
}
})
This works because the context inside get
is an instance Person
, so the arrow function will refer to it correctly.