简体   繁体   中英

How do I assign an object to an array within another object?

I'm taking on the blackjack challenge and coming up with my own code. So here's what I've got so far ... my card generator ...

var card = {
    suit: null,
    face: null,
    value: null,
    generateSuit: function (x) {
        if (x == 0) this.suit = 'Clubs';
        if (x == 1) this.suit = 'Diamonds';
        if (x == 2) this.suit = 'Hearts';
        if (x == 3) this.suit = 'Spades';
    },
    generateFace: function (y) {
        if (y > 1 && y < 11) this.face = y,
        this.value = y;
        else {
            if (y == 1) this.face = 'Ace', this.value = 1;
            if (y == 11) this.face = 'Jack', this.value = 10;
            if (y == 12) this.face = 'Queen', this.value = 10;
            if (y == 13) this.face = 'King', this.value = 10;
        };
    },
    generateCard: function () {
        var x = Math.floor(Math.random() * 4);
        var y = Math.floor(Math.random() * 13 + 1);
        this.generateSuit(x);
        this.generateFace(y);
    },
}

This works fine, I'm just including it because the next part has me stumped so I figured I'd leave nothing out.

Here's where things go south - within my 'hand' (posted next), I'm using my 'generateCard()' function to set the values of 'card' and then store them in an array named 'storecard [ ]'.

var hand = {
    storecard: [],
    count: 0,
    total: 0,
    hitCard: function () {
        this.count += 1;
        card.generateCard();
        this.storecard[this.count] = Object.create(card);
        this.total += this.storecard[this.count].value;
        this.logHand();
    },
    logHand: function () {
        console.log(this.storecard[this.count].face + ' of ' + this.storecard[this.count].suit);
        console.log('Value = ' + this.storecard[this.count].value);
        console.log('Count = ' + this.count);
        console.log('Hand Total = ' + this.total);
    }
}

The idea being that every time a card is hit (added to the hand), 'hand' will stash it (and all of its properties - suit, value, etc.) in storecard[index == hand count, clever eh?]

This way, I can retrieve any attribute of any card in the hand whenever and however I please by accessing storecard[index] .

Well, not so much. Run the code and that array is the only thing that bites the dust...

var me = Object.create(hand);
var dealer = Object.create(hand);

me.hitCard();
me.hitCard();

My 'logHand()' function indicates all is well!

"5 of Hearts"     
"Value = 5"       
"Count = 1"       
"Hand Total = 5"  
"2 of Clubs"      
"Value = 2"       
"Count = 2"       
"Hand Total = 7"

But alas, somehow - the 'storecard' array has failed. Upon further examination we discover:

me.storecard[1].value
2
me.storecard[2].value
2

storecard[1] should be holding my 5 of hearts, but has been overwritten by the 2 of clubs! And if that isn't horrifying enough ...

dealer.storecard[1].value
2
dealer.storecard[1].value
2

I haven't even touched the dealer object yet!

Now every other variable in both my hand and the dealer hand are congruent with reality - the array is the only problem.

What am I doing wrong here?

The problem is your expectation of what Object.create() does.

It creates a shallow clone of the object. Arrays are assigned by reference, not value.

For example

var arrayOne = [];
var arrayTwo = arrayOne;
arrayOne.push('3');
alert(arrayTwo[0]); // This will give you 3. Both variables are pointing to the same array

So too:

   var handTemplate = {
       childArray: []
   };

   var handOne = Object.create(handTemplate);
   var handTwo = Object.create(handTemplate);
   // At this point, handTemplate, handOne and handTwo all point to the same array

   handOne.childArray.push('3');
   alert(handTwo.childArray([0])); // Again, you'll see 3, because there's only one array

One solution is to create hand using a dedicated function:

function createHand() {
    return {
        storecard: [], // Now we get a brand new array every time createHand is called
        count: 0,
        total: 0,
        hitCard: function () {
            this.count += 1;
            card.generateCard();
            this.storecard[this.count] = Object.create(card);
            this.total += this.storecard[this.count].value;
            this.logHand();
        },
        logHand: function () {
            console.log(this.storecard[this.count].face + ' of ' + this.storecard[this.count].suit);
            console.log('Value = ' + this.storecard[this.count].value);
            console.log('Count = ' + this.count);
            console.log('Hand Total = ' + this.total);
        }
    };
}

var me     = createHand();
var dealer = createHand();

well this is a different approach but a good way to do it.
i've written the code in a way you could learn something.
as example.. you could fully get rid of the count variable since its equal to storecard.length.
mind however that you still need to prevent dublicate cards. you can easily do it by generating all cards first, putting it into an array and then splicing cards out of it randomly untill the stack is empty.

var Card = function () {
    this.suit = null;
    this.face = null;
    this.value = null;
    this.generateCard();
};

Card.prototype = {
    generateSuit: function (x) {
        this.suit = ["Clubs", "Diamonds", "Hearts", "Spades"][x];
    },
    generateFace: function (y) {
        this.value = Math.min(10, y);
        switch (y) {
            case 1:
                this.face = "Ace";
                break;
            case 11:
                this.face = "Jack";
                break;
            case 12:
                this.face = "Queen";
                break;
            case 13:
                this.face = "King";
                break;
            default:
                this.face = y;
                break;
        }
    },
    generateCard: function () {
        this.generateSuit(Math.floor(Math.random() *4));
        this.generateFace(Math.floor(Math.random() *13 +1));
    }
}

var Hand = function () {
    this.storecard = [];
    this.count = 0;
    this.total = 0;
};

Hand.prototype = {
    hitCard: function () {
        this.count++;
        var card = new Card();
        this.storecard.push(card);
        this.total += card.value;
        this.logHand();
    },
    logHand: function () {
        var card = this.storecard[this.storecard.length -1];
        console.log(card.face + ' of ' + card.suit);
        console.log('Value = ' + card.value);
        console.log('Count = ' + this.count);
        console.log('Hand Total = ' + this.total);
    }
}

outcome will be:

> var me = new Hand();
undefined
> var dealer = new Hand();
undefined
> me.hitCard();
Ace of Hearts
Value = 1
Count = 1
Hand Total = 1
undefined
> me.hitCard();
6 of Diamonds
Value = 6
Count = 2
Hand Total = 7
undefined
> me.storecard
[ { suit: 'Hearts',
    face: 'Ace',
    value: 1 },
  { suit: 'Diamonds',
    face: 6,
    value: 6 } ]

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