Reputation: 91
I'm experimenting with a few aspects of Javascript's inheritance via a question I came across:
Create a reservation system which books airline seats or hotel rooms. It charges various rates for particular sections of the plane or hotel. Example, first class is going to cost more than coach. Hotel rooms have penthouse suites which cost more. Keep track of when rooms will be available and can be scheduled.
I'm working on the Hotel room problem.
I've decided to go with a single room base object with one data member called 'duration' which keeps track of the number of days the room is booked for, and two methods : book and checkout .
I have a derived object 'SingleRoom' which inherits from SingleRoom.
Here's the code :
function Room(duration){
this.duration = duration;
}
Room.prototype.book = ()=>{
if (this.prototype.count > 0){
this.prototype.count -= 1;
return true;
}
else {
return false;
}
}
Room.prototype.checkOut = ()=>{
this.prototype.count += 1;
console.log("Room checked out");
}
function SingleRoom(duration){
this.price = 1000;
}
SingleRoom.prototype = new Room();
SingleRoom.prototype.constructor = SingleRoom;
SingleRoom.prototype.count = 3;
var sr1 = new SingleRoom(2);
if(sr1.book() === false){
console.log("Could not book room");
}
I'm getting the following error at 'this.prototype.count' : Cannot read property count of undefined
Any idea what the issue is ?
Thanks!
Upvotes: 1
Views: 109
Reputation: 1074028
You're confusing functions with instances (or at least, properties you use with functions with ones you use with instances; which is really easy to do). The prototype
property is used on a constructor function. It refers to the prototype object that will be assigned as the underlying prototype (called [[Prototype]]
in the spec) of objects created via that constructor. It isn't (confusingly!) a reference to an object's prototype; to get that (the thing the spec calls [[Prototype]]
), you use Object.getPrototypeOf(theObject)
, but it's relatively rare you want to.
This may help clarify that relationship:
function Thing(name) {
this.name = name;
}
Thing.prototype.say = function() {
console.log(this.name);
};
var t = new Thing("Ben");
console.log(t.prototype); // undefined, `t` has no `prototype` property
console.log(Thing.prototype); // an object with `say`
t.say(); // "Ben"
console.log(Object.getPrototypeOf(t) === Thing.prototype); // true
The other issue is that you're using arrow functions to define functions on prototypes, which won't work; the point of arrow functions is that they close over this
, but for a prototype function, you want this
set by how the function is called.
If you're using ES2015 (e.g., transpiling with Babel or similar), you can use the nice, new, easy syntax. I've had to guess at what count
is supposed to be; I put it on Room
instances:
class Room {
constructor(duration){
this.duration = duration;
this.count = 3;
}
book() {
if (this.count > 0) {
this.count -= 1;
return true;
}
else {
return false;
}
}
checkOut() {
this.count += 1;
console.log("Room checked out");
}
}
class SingleRoom extends Room {
constructor(duration){
super(duration);
this.price = 1000;
}
}
var sr1 = new SingleRoom(2);
if (sr1.book() === false){
console.log("Could not book room");
}
If you want to use ES5, here's a translation with notes:
function Room(duration) {
this.duration = duration;
this.count = 3;
}
// Note we *don't* use arrow functions for prototype functions; it's important
// for them to get `this` by how they're called.
Room.prototype.book = function() {
if (this.count > 0) {
this.count -= 1;
return true;
}
else {
return false;
}
};
Room.prototype.checkOut = function() {
this.count += 1;
console.log("Room checked out");
};
// Derive SingleRoom from Room
function SingleRoom(duration) {
Room.call(this, duration); // Necessary to init Room
this.price = 1000;
}
SingleRoom.prototype = Object.create(Room.prototype); // NOT `new Room()`
SingleRoom.prototype.constructor = SingleRoom;
var sr1 = new SingleRoom(2);
if (sr1.book() === false){
console.log("Could not book room");
}
Upvotes: 2
Reputation: 141829
You should only use the prototype
property on constructor functions. This is correct:
SingleRoom.prototype = new Room();
SingleRoom.prototype.constructor = SingleRoom;
SingleRoom.prototype.count = 3;
But you shouldn't use it on individual objects. The prototype chain is searched automatically when you access properties that aren't defined on the immediate object. Everywhere that you have this.prototype.count
change it to this.count
and it will work properly.
Upvotes: 3