Factory Functions

In the last post I mentioned that the code I used was a bit copy-pastey. Namely that player and monster looked exactly the same.

var player = {  
    name: 'player',
    att: 2,
    def: 2,
    hp: 10,
    attack: function (monster) {
        monster.hp -= Math.floor(Math.random()*this.att) - Math.floor(Math.random()*monster.def)
    }
}

var monster = {  
    name: 'monster',
    att: 2,
    def: 2,
    hp: 10,
    attack: function (player) {
        player.hp -= Math.floor(Math.random()*this.att) - Math.floor(Math.random()*player.def)
    }
}

Here's how we fix that:

var between_0_and = (number) => Math.floor(Math.random() * number)

var character = (name, att, def, hp) =>  
    ({
        name: name,
        att: att,
        def: def,
        hp: hp,
        attack: function (enemy) {
            enemy.hp -= between_0_and(this.att) - between_0_and(enemy.def)
        }
    })

characteris a function that returns an object. (Note we have to put parentheses around the curly brackets, otherwise the JavaScript interpreter will think the object is a function).

This is what's called a factory function. Just a fancy term for a function who's job is to return a new object.

Here's our modified game:

for(var i = 0; i < 10; i++) {  
    let player = character('Eldrith The Large', 2, 2, 15)
    let monster = character('the goblin', 5, 1, 5)

    while (player.hp > 0 && monster.hp > 0) {
        player.attack(monster)
        monster.attack(player)
    }
    if(monster.hp > 0) {
        console.log(`${monster.name} wins!`)
    } else if(player.hp > 0) {
        console.log(`${player.name} wins!`)
    } else {
        console.log(`both ${player.name} and ${monster.name} are losers!`)
    }

    monster.hp = 10
    player.hp = 10
}

A few notes about the changes...

let is like var, but, unlike var, variables declared with let are scoped within blocks like for and while loops or if statements. (You'll need to make the first line of your JavaScript file 'use strict' to make let available).

This bit, ${monster.name}, is how ES2015 does templating. It should be familiar to Ruby developers and not completely foreign to PHP and Perl programmers. Just use ticks instead of double or single quotes and wrap a ${} around any variable to put its value in the string.

You might be wondering how to keep an object's methods and members private. All will be revealed next time!

Looking for a software developer?