That Javascript has (extended) class!
Tags: javascript
Published: 2021-05-07 16:17:35

Let's talk extending classes in JavaScript.

I wrote a single page JavaScript game that I called Gibberish Cards. It's kinda like War... but dumber. 

It didn't use a typical card deck, and the names of the cards were user defined. This mean I needed a list of what cards were in the game and a subset of those cards that had names. In addition I needed to know which cards a user had in his draw pile and which cards a computer had in his draw pile. I also needed to know which cards the user and computer had in their discard pile. That's 6 arrays of card objects!

So I created a Deck class.

## A Simple Class

```
class Deck {

    constructor() {
        this.unplayedCards = []
    }

    addCardtoDeck(card) {
        this.unplayedCards.push(card)
    }

    
    findCard(id) {
        return this.unplayedCards.find(card => card.id === id)
    }

}
```

I called the array of cards **unplayedCards** because I needed to know which cards had not already been used in the game. I had two functions in this class **addCardtoDeck** which was great when the game first started as I filled in all those different decks I talked about. And occasionally I need to find a card object so the **findCard** function was very useful.

But I also needed to keep track of what named cards existed. The computer only ever had named cards, and I didn't need to keep the named and unnamed cards separate for the user so I only needed a list of all the named cards in the game before starting.

Rather then keep track of those named cards in all Deck classes I extended the **Deck** class to an **AllCards** class.

## Extending and Using super

```
class AllCards extends Deck {

    constructor() {
        super()
        this.namedCards = []
    }

    addCardtoDeck(card) {
        super.addCardtoDeck(card)
        if (card.name) {
            this.namedCards.push(card)
        }
    }

    resetNamed() {
        this.namedCards = this.unplayedCards.filter(card => card.name)
    }

}
```

Because this extends from **Deck** I had access to the **findCard** and **addCardtoDeck** function. My constructor needed both an **unplayedCards** array and a **namedCards** array. I used the code from the Deck class by calling the **super()** method in the constructor. 

I determined which cards were named as I filled cards into those arrays via **AddCardtoDeck** so I also had to extend that function. You can see in the extended function I call **super.addCardtoDeck(card)** to add a card to my **unplayedCards** array but then I have new code where I add any named cards to the **namedCard** array.

This would be a pointless array in the user's deck and the computer's deck so I avoided the two extra array of card objects.

I also created a function just in the **AllCards** class called **resetNamed()** which is useful after a game ends. If a user wants to play again I don't want to re-upload all the card details from the database so it recreates the **namedCards** array with any cards that got named during the most recent game. 

There was also a lot of functions I used in the two game decks that I never needed to use for the repository of all cards so I extended another class from **Deck**.

## Another Extended Class

```
class PlayableDeck extends Deck {

    constructor() {
        super()
        this.playedCards = []
    }

// here is where I placed all the functions 
// only applicable to this class.

}

```

Similar to the **AllCards* class this extends from **Deck**, uses super to create a **this.unplayedCards** array but then also creates an array for game decks that keeps track of which cards have been played since the last reshuffle. A discard pile, if you will. I called that **playedCards**.

Now that I had a **PlayableDeck** class I was able to create a slew of functions for game play that did not need to sit in the **Deck** class.

* **drawCard()** - randomly draws an unplayed card
* **moveCardToPlayed(card)** - moves a card (say that card I got from drawCard()) into the playedCards array.
* **removeCardFromDeck()** - removes a card from played. This is used when your opponent takes your card.
* **totalCards()** and **totalUnplayedCards()** to keep track of draw and discard piles. These are also critical to know when you need to reshuffle or when you've lost the game!
* **clear()** - this function is clearing all cards after a game ends so you can start a new game cleanly.

## 3 Uniquely Similar Objects!

By extending the class I was able to have 3 Deck objects used in my code that didn't have functions or arrays baked in they would never use. It made the code cleaner and made testing easier while I coded the gameplay functionality.

Extend your classes! It's easy!