简体   繁体   中英

Javascript prototypal inheritance

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!

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.

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 (eg, 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");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM