Avoid global variables

Hi,
I am coding memory game. I would like to avoid assign complex values.
My code is below:



const game = document.getElementById('game');

let firstCard = 1; // at the beginning, firstCard and second cards are setting to 'null'
let secondCard = 2;


const config = {
    height: '100px',
    width: '100px',
    src: 'pictures/back-card.jpg',
    position: 'absolute',
    cardsize: 100,
    cardspacing: 10,
    columns: 4,
    rows: 3,
    time: 1000
}


function createGrid() {  //invoked this f. in html body
    const cardsIndexes = [] // an empty array, where we are going to push cards
    for (let i = 0; i < config.columns * config.rows / 2; i++) { // 4 * 3 / 2 = 6 cards
        cardsIndexes.push(i); //we are pushing one index / 
        cardsIndexes.push(i); // and then second to 'let cardsIndexes'        
    }

    const shuffleCards = [];
    while (cardsIndexes.length > 0) {
        let random = Math.floor(Math.random() * cardsIndexes.length) // Math.random() is drawing cards form 1 - 12, Math.floor is downward to its nearest integer.
        shuffleCards.push(cardsIndexes[random]); // we are pushing choosed card to empty 'const shuffleCards' from 'cardsIndexes'
        cardsIndexes.splice(random, 1); // we are putting one drawn card to 'let cardsIndexes'
    }

    for (let left = 0; left < config.rows; left++) { // 3 rows
        for (let top = 0; top < config.columns; top++) { // 4 columns
            renderCard(shuffleCards.pop(), left, top); // here, we are taking (remove) drawn card from 'let shuffleCards = []'
        }
    }
}

function renderCard(cardNum, top, left) {
    let card = document.createElement('img');
    card.num = cardNum;
    card.src = config.src;
    card.style.position = config.position;
    card.style.top = (top * (config.cardsize + config.cardspacing) + config.cardspacing) + 'px';
    card.style.left = (left * (config.cardsize + config.cardspacing) + config.cardspacing) + 'px';
    card.style.height = config.height;
    card.style.width = config.width;
    card.onclick = turnCard;
    game.appendChild(card); // we are adding cards to game  
}

function turnCard(e) {
    let card = e.target;
    if (firstCard === 1) {
        firstCard = card;
        card.src = 'pictures/card' + card.num + '.jpg' // we have to write here 'card.src' to declare exact time (1s) for two clicked cards
    } else if (secondCard === 2) {
        secondCard = card;        
        card.src = 'pictures/card' + card.num + '.jpg' //         
        setTimeout(checkCards, config.time) // time of showing two cards <= 1s.
    }
}

function checkCards() {
    if (firstCard.num === secondCard.num) { // if cards are the same,
        game.removeChild(firstCard); //  remove them
        game.removeChild(secondCard);
    } else { // if not, turn back
        firstCard.src = 'pictures/back-card.jpg';
        secondCard.src = 'pictures/back-card.jpg';
    }
    firstCard = 1; // we are resetting the firstCard
    secondCard = 2; // we addingre resetting the secondCard
}

Lines:

  • firstCard = 1;
  • secondCard = 2;
    In global scope firstCard =1, secodnCard = 2
    I would like to avoid this, because in future this can cause troubles in let card.

My teacher suggested to use [..card] or Object.assign({}...card), but this is working only with objects. Do you have different ideas?

The much bigger problem is that firstCard / secondCard variables constantly switch their type between HTMLElement and integer.

I would avoid those variables altogether and use an array of card objects. This has the advantage that you can a) save card state (e.g. front/back, image, …) on the card object itself b) use the array methods to easily to find cards with certain properties and c) you can add behaviour to the cards.

also have a look at the Observer Pattern.

Thanks for your time. What do you mean exactly by using array method?

I did small changes by assigning firstCard and secondCard to {...card} (not to card as before), game is not working correctly. Cards are not turning back.

Additionally, I tried to code object like:

let pairs = {
firstCard: 1,
secondCard: 2
}

and I changed firstCard for pairs.firstCard, secondCard for pairs.secondCard everywhere to get to the value and key of the object. I got errors like: 'Failed to execute ‘removeChild’ on ‘Node’: parameter 1 is not of type ‘Node’.
_ at checkCards’_

e.g. Array.filter()

That doesn’t improve the issue in any way. You have to get rid of the global variables completely.

as predicted:

Admittedly a bit eccentric, but while working up code I often append the type to the name so I will know the type at a glance. eg.

user_arr 
id_int 
admin_bool 
name_str 

etc. Maybe changing the names in a similar fashion would be a help in keeping track of what’s what when.

3 Likes

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.