Aaron
Aaron

Reputation: 3255

Using Object.create() the correct way

Learning Javascript I am finding different ways for creating objects. Seems that the way forward is using Object.create()

It's pretty hard to find a solid answer on best practises for using Object.create() as even the specific Object.create() articles seem to do things slightly different.

What I want to do is create multiple objects with their own encapsulated data.

I like to use encapsulation and what seems to work for me is something like

function Foo() {
    var message = "Hello";

    return {
        bar:bar
    }

    function bar(){ 
        return message; 
    }
}

World = (function(){ 
    var obj = Foo();
    var tank = Object.create(obj);

    return {
        baz:baz
    }

    function baz(){ 
        alert(tank.bar()); 
    }

})();

Running World.baz() works as expected but I am still not sure if I am doing this right.

All answers will be appreciated, thanks.

Upvotes: 2

Views: 278

Answers (3)

Noble Mushtak
Noble Mushtak

Reputation: 1784

I would suggest using constructors to encapsulate data. If you really need to use Object.create(), you need to create a constructor-prototype system with Object.create(). However, in any case, you're just calling .bar() from the result of Foo() in the .baz() method of World. That does not mean World should point to the result of Foo().

Object.prototype.__construct = function() {
    //This is the default constructor from any new object. We change it to change the constructor of objects as we go along. We could make no __construct method on Object.prototype because it doesn't do anything, so we're not going to call it, but we're going to define it anyway since we want all objects to have a __construct method, even if they don't define a new one on top of the default.
};
//Object.prototype is our default object. We add methods to object to change the prototype of objects as we go along.

var Foo = {}; //Any object that doesn't inherit from anything must inherit from Object.prototype. We do this by just setting it to {} (or new Object()).
//If we're going to define a new constructor, we need to call it _after_ we've defined it.
Foo.__construct = function() {
    var message = "Hello!";
    this.bar = function() {
        return message;
    }
};
Foo.__construct();
Foo.bar() //returns "Hello!"
//Note that message is encapsulated and _cannot_ be accessed through Foo itself.

var World = {}; //World _does not_ point to Foo. It simply calls a method of Foo in one of its methods.
World.__construct = function() {
    //Now, if the method of Foo we're going to call in the method of World is going to alter Foo, then we should make a copy of Foo using Object.create(). The method we're going to call isn't _actually_ going to alter Foo, but it's good practice to make a copy because it _could_ if we made it so.
    var obj = Object.create(Foo);
    //Because Foo has been constructed and obj is a copy of Foo, we don't need to construct obj. We only need to construct an object if we define a new constructor property.
    this.baz = function() {
        alert(obj.bar());
    };
};
World.__construct();
World.baz() //alerts "Hello!"
//Note that obj is encapsulated within World. obj points to Foo, but again, World _does not_ point to Foo.

Upvotes: 0

Rich Hildebrand
Rich Hildebrand

Reputation: 1885

Try this approach for creating javaScript objects that encapsulating data. As you can see each instance of Foo has its own properties and state.

    var Foo = function() {

        var Foo = function Foo(customMessage) {
            this.message = customMessage || "Hello";
        }

        Foo.prototype.message;

        Foo.prototype.bar = function(){ 
            return this.message; 
        }

        return Foo;
    }();

    var tank1 = new Foo();
    var tank2 = new Foo("Goodbye");

    alert(tank1.bar());
    alert(tank2.bar());

Upvotes: 0

Mercury
Mercury

Reputation: 350

Generally in javascript you want to create objects like so:

var obj = {};
obj.someProperty = 'someValue';
obj.someOtherProperty = 'someOtherValue';

Or, you could use object literal notation, like this:

var obj = {
    someProperty: 'someValue',
    someOtherProperty: 'someOtherValue'
};

The Object.create function is an interesting one. Yes, it does create an empty object, but it isn't like the objects defined above. Instantiating and object with Object.create will give the new empty object inheritance up to the parameter you give the Object.create function. For instance, if we define an object as:

var actions = {
    shout: function(message){
        console.log(message.toUpperCase() + '!');
    }
}

And then create a new object with Object.create():

var newObject = Object.create(actions);  // creates a new object: newObject = {};

newObject will not contain any of it's own properties, but it will be able to access the properties of the parent actions object. After defining those object, try this out:

newObject.hasOwnProperty('shout');    // returns false
newObject.shout('Hello!');    // logs 'HELLO!!'

This example just goes to show how inheritance works from the newly created object to it's parent. This can be extremely useful, but make sure you specifically want that behavior before creating objects with Object.create-- otherwise, better be safe and use one of the two other methods above.

Hope that helps!

Edit:

Alternatively, if you're just trying to create many separate instances of the same object, you can create a constructor and invoke it with the new keyword, like this:

var Tank = function(speed, durability){
    this.speed = speed;
    this.durability = durability;
    this.location = 0;
    this.shoot = function(){
        console.log('Pew pew');
    };
    this.move = function(){
        this.location += speed;
    };
}

var myTank = new Tank(5, 15);    // creates new tank with speed 5 and durability 15,
                                 // that also has all the default properties and methods,
                                 // like location, shoot, and move.

var yourTank = new Tank(7, 12);  // instantiates a different tank that myTank, with it's
                                 // own speed and durability properties, but also has the
                                 // default location, shoot, and move properties/ methods

var enemyTank = new Tank(10, 25);// instantiates yet another, unique tank with it's own 
                                 // unique values for speed and durability, but again with
                                 // the default location, shoot, and move properties/methods

Upvotes: 1

Related Questions