Search code examples
javascriptoopprototypeprototypal-inheritanceprototype-programming

Struggling with Prototypes/Inheritance in JavaScript


I have a little practice project, where I am developing a Blackjack Game. I am using JS prototypes for OOP purposes, which works great so far. I have a Game, Card and Hand (all the cards a player has) prototype object. Now I have a problem with my Hand prototype. It returns my card values "undefined". I don't know what is wrong since my Hand constructor returns the right values.

I have to admit my understanding of JS prototypes is maybe not the best yet, so this might be my problem which I am struggling with?!

This is the relevant snippet from my code:

var suits = ["club", "diamond", "heart", "spade"];
var cardValue = ["ace", 2, 3, 4, 5, 6, 7, 8, 9, "jack", "queen", "king"];

function Game() {
}

Game.prototype = {

    deal: function() {
        var cardSuit = Math.floor(Math.random() * suits.length);
        var cardNumber = Math.floor(Math.random() * cardValue.length);

        return cardSuit, cardNumber;
    },


    createHand: function() {
        var newHand = new Hand();
        var userCards = newHand.getHand();

        return newHand;
    }

};

var card1, card2, handCards;

function Hand() {
    var card1 = Game.prototype.deal(); //works! return two values
    var card2 = Game.prototype.deal(); //works! return two values
    var handCards = [card1, card2]; //works! creates array from card 1 and 2
}

Hand.prototype = {

    getFirstCard: function() {
        return card1; // IS "UNDEFINED"!
    },

    getSecondCard: function() {
        return card2; // IS "UNDEFINED"!
    },

    getHand: function() {
        return handCards; // IS "UNDEFINED"!
    }
};

Can you please help me? Thank you very much in advance!


Solution

  • You are declaring some global variables without assigning values:

    var card1, card2, handCards;
    

    Then in hour Hand() function you declare variables of the same name that are local to that function:

    function Hand() {
        var card1 = Game.prototype.deal();
        // etc.
    

    Then your other functions try to access the globals which have never been assigned a value:

    getFirstCard: function() {
        return card1; // IS "UNDEFINED"!
    },
    

    If you want to access these values from the methods of your "class" these variables should be instance variables:

    function Hand() {
        this.card1 = Game.prototype.deal(); //works! return two values
        this.card2 = Game.prototype.deal(); //works! return two values
        this.handCards = [this.card1, this.card2]; //works! creates array from card 1 and 2
    }
    ...
    getFirstCard: function() {
        return this.card1;
    },
    

    ...and so forth in the other methods that use those variables. And you can delete the var card1, card2, handCards; line.

    Or it might be tidier to do this:

    function Hand() {
        this.handCards = [Game.prototype.deal(), Game.prototype.deal()];
    }
    ...
    getFirstCard: function() {
        return this.handCards[0];
    },
    getSecondCard: function() {
        return this.handCards[1];
    },
    

    (There are other problems in your code, e.g.:

    • your cardValue array is missing 10
    • return cardSuit, cardNumber; will just return cardNumber
    • your createHand() function declares and sets a userCards variable that is never used
    • I don't see the point in having a Game() constructor if you never instantiate any Game objects and just call the methods of the prototype like Game.prototype.deal()
    • you don't keep track of what cards are left in the deck, so (however unlikely) the random card selection could deal the same card twice

    ...and so forth.)