bobbyz
bobbyz

Reputation: 5046

How to create an object inside class static method

I'm starting to learn more about static methods in classes, and was wondering if the following is doable:

My questions: 1. Is this a terrible approach to doing this? And if not, 2. How do you create a new instance inside the static method?

My first thought is that you can just have the static method return an object and do whatever logic you want to randomize the values of that object, but I wasn't sure if there was a better way. (I think that object would be outside the prototype chain of instances created with new Monster(...)?)

Here's what I came up with for my first attempt, but this imperatively creates the Monster, mimicking the Monster class:

class Monster {
    constructor(hp) {
        this.hp = hp;
    }

    static create() {
        const obj = Object.create(Monster.prototype);
        obj.hp = Math.floor(Math.random() * 100);
        return obj;
    }

    attack(obj) {
        const randDamage = Math.floor(Math.random() * 10);
        console.log(`Monster deals ${randDamage} damage!`);
        obj.hp -= randDamage;
    }
}


const monster = Monster.create();
const me = {hp: 100};
monster.attack(me);
console.log(me);  // { hp: 91 }

Is there a way to implement create() that uses the Monster class? Or is this the right way to do this?

Upvotes: 3

Views: 9247

Answers (1)

jfriend00
jfriend00

Reputation: 707248

A function that returns an instance of an object is commonly referred to as a "factory function". This is a common design pattern for certain types of objects.

For what you are doing, you have a couple choices:

  1. You can create a factory function that makes and returns an object that is pre-set up a certain way or a random way.

  2. You can create a constructor variant (a set of parameters you can pass to a constructor) that will cause it to create the type and configuration of your object that you want.

Either of these can work equally well.

Is this a terrible approach to doing this?

No. A factory function is a perfectly reasonable way of doing things. Normally, I would first just consider letting the constructor do the work for you and not use a factory function, but sometimes there are good reasons for collecting a certain sequence that builds your object a certain way into a factory function instead of the constructor.

How do you create a new instance inside the static method?

You use new just like anywhere else.

Is there a way to implement create() that uses the Monster class?

Yes. You just use new inside your static method to create the object.

// since your constructor already accepts an hp parameter as an argument
// you can just create a random hp value and pass it to the constructor
static create() {
    let hp = Math.floor(Math.random() * 100);
    return new Monster(hp);
}

But, you also could just modify your constructor so that if no argument is passed, then the constructor itself creates a random value for it and not use a static factory function at all:

class Monster {
    constructor(hp) {
        if (hp === undefined) {
            this.hp = Math.floor(Math.random() * 100);
        } else {
            this.hp = hp;
        }
    }

    // rest of class definition here

}

And, then just use the constructor to create your object:

// create monster object with random hp value
const monster = new Monster();

Or, if your arguments are simple enough, you can use an ES6 default value:

class Monster {
    // supply default value for hp parameter if not present
    constructor(hp = Math.floor(Math.random() * 100)) {
        this.hp = hp;
    }
}

Allow someone to create a monster instance by passing all the properties they want the monster to have

This is often done by passing in an object to the constructor and whatever properties are present on the object, those are used to initialize features of the object. If a property is not present on the object passed into the constructor, then the constructor will use a default value.

class Monster {
    constructor(options) {
        if (options.hp === undefined) {
            this.hp = Math.floor(Math.random() * 100);
        } else {
            this.hp = options.hp;
        }
        // similar logic can be used for other properties on the options object

    }

    // rest of class definition here

}

This examples shows code examining each specific property on the object, but this can be somewhat automated too by copying all properties on the passed-in object to the newly created object or by creating a whitelist of property names and copying any that are present in both the whitelist and on the object.

Or, the passed in object can be merged with a set of default values for the properties and then merged into the new object. There are lots of ways to do it depending upon what specific properties you have and how you want them treated if they are or are not present.

Upvotes: 4

Related Questions