mikedidthis
mikedidthis

Reputation: 4897

Replicating constructors and new with Object.create()

From my limited experience with OOP javascript, a common way to handle multiple objects with different properties but the same methods would be using a constructor as follow:

function Animal ( type ) {
    this.type = type
};
Animal.prototype.sayHello = function () {
    return 'Hi, I am a ' + this.type
};
var goat = new Animal( 'Goat' );

My understanding here is goat would inherit / have a reference to the functions of Animal.

I presume I can replicate the above with the following object literal notion:

var Animal = {
    type : '',
    sayHello : function () {
        return 'Hi, I am a ' + this.type
    }
}
var goat = Object.create( Animal );
goat.type = 'Goat';

Is the inheritance to Animal lost here, or is Goat still referencing Animal for methods?

I would like to know if there are any issue using Object.create() instead of new to replicate a constructor / class. Is there a perf offset or any reason to carry on using new?

Any advice would be appreciated, I am happy to add to the question if clarification is needed.

Updated Object Creation

var Animal = {
    sayHello : function () {
        return 'Hi, I am a ' + this.type
    }
}
var goat = Object.create( Animal, { 'type' : { value: 'goat' } } );

Upvotes: 2

Views: 316

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074238

...a common way to handle multiple objects with different properties but the same methods would be using a constructor...

Yes, the other common way being (as you've seen) Object.create.

My understanding here is goat would inherit / have a reference to the functions of Animal.

Not quite. In the new Animal expression, goat gets assigned the object referenced by Animal.prototype as its underlying prototype. There is no direct connection to Animal, just to Animal.prototype. (Animal.prototype has a reference back to Animal via its constructor property, in the normal course of things, although that link can get broken if someone assigns a new object to Animal.prototype.)

Is the inheritance to Animal lost here, or is Goat still referencing Animal for methods?

In your non-constructor example, goat gets Animal as its underlying prototype, so for any property not found on goat itself, the JavaScript engine will look at Animal to see if it has it. In your example, that means that goat is using sayHello from Animal, but not type, because goat has its own type.

The rough equivalent of this:

function Animal ( type ) {
    this.type = type
};
Animal.prototype.sayHello = function () {
    return 'Hi, I am a ' + this.type
};
var goat = new Animal( 'Goat' );

...using Object.create to set the prototype instead looks like this:

var animalPrototype = {
    sayHello: function () {
        return 'Hi, I am a ' + this.type
    }
};
function createAnimal(type) {
    var rv = Object.create(animalPrototype);
    rv.type = type;
    return rv;
};
var goat = createAnimal( 'Goat' );

Re your comment:

Would there be any issue including animalPrototype inside createAnimal and then calling Object.create(this.animalPrototype)?

If you mean this:

function createAnimal(type) {
    var animalPrototype = {                       // Issue #1
        sayHello: function () {
            return 'Hi, I am a ' + this.type
        }
    };
    var rv = Object.create(this.animalPrototype); // Issue #2
    rv.type = type;
    return rv;
};
var goat = createAnimal( 'Goat' );

...then yes, there are two issues:

  1. You'd create a new animalPrototype for each call to createAnimal, which defeats the purpose, and 2. this within the call to createAnimal will either be the global object (loose mode) or undefined (strict mode), so this.animalPrototype probably isn't the expression you want.

You could do this:

function createAnimal(type) {
    var rv = Object.create(createAnimal.proto);
    rv.type = type;
    return rv;
};
createAnimal.proto = {
    sayHello: function () {
        return 'Hi, I am a ' + this.type
    }
};
var goat = createAnimal( 'Goat' );

Could be confusing for people, of course, since that looks so much like a constructor function.

Upvotes: 6

Related Questions