2

While reading other people's source code and various articles over the web, I found that when different people use "object-oriented-style" programming in JavaScript, they often do it quite differently.

Suppose, I want to create a tiny module having 1 property and 1 function. I've seen at least 4 approaches to this task:

// Option 1
var myObject1 = {
    myProp: 1,
    myFunc: function () { alert("myProp has value " + this.myProp); }
};

// Option 2
var myObject2 = function () {
    return {
        myProp: 1,
        myFunc: function () { alert("myProp has value " + this.myProp); }
    };
}();

// Option 3
var MyObject3 = function () {
    this.myProp = 1;
    this.myFunc = function () { alert("myProp has value " + this.myProp); }
};
var myObject3 = new MyObject3();

// Option 4
var MyObject4 = function () { };
MyObject4.prototype.myProp = 1;
MyObject4.prototype.myFunc = function () { alert("myProp has value " + this.myProp); };
var myObject4 = new MyObject4();

All these approaches are syntactically different but seem to produce objects that can be used in the same way.

What's the semantic difference between them? Are there cases when for some reason I should choose one of these options over all the rest?

Andre Borges
  • 1,360
  • 14
  • 37
  • 1
    Option 2 is pointless unless you add more code before the return statement, perhaps to add some variables that would be accessible from within the methods of the returned object - otherwise it's just option 1 wrapped up in a redundant IIFE. Options 1 & 2 create singletons, whereas options 3 & 4 give you constructors that can be used to create multiple instances. And you've missed option 5, which would be like 3 & 4 but with myProp set per instance and myFunc() set on the prototype. – nnnnnn Apr 25 '16 at 09:07
  • Possible duplicate: [How to “properly” create a custom object in JavaScript?](http://stackoverflow.com/questions/1595611/how-to-properly-create-a-custom-object-in-javascript) – Yogi Apr 25 '16 at 09:09

2 Answers2

3

myObject1 is an object literal (singleton). Useful in cases where you want to have just one object of this type. Look at it as a static object.

myObject2 returns an object literal. So right after doing var foo = myObject2(), the variable foo will hold the result { myProp: 1, myFunc: function(){...} } with reference to the parent function that has executed. This is called a closure. This can be used to define a public API or modules, for example.

i.e.:

var foo = (function(){
     var privateProp = "I am a private property";

     // the object below is returned, privateProp is accessible 
     // only through foo.publicProp
     return {
        publicProp: privateProp            
     }
})();

The privateProp property is now accessible through foo.publicProp.

MyObject3 and MyObject4 are constructor functions. By using the new keyword before the function call, you tell JavaScript to create an instance of that object. This means that every new object created this way will inherit properties and methods from the object definition.

The difference between MyObject3 and MyObject4 is that in the case of the former, every instance of that object will have its own copy of the myProp and myFunc properties, whereas the latter will only reference those properties. That means that no matter how many instances of object MyObject4 you create, there will be only one of myProp and myFunc.

I recommend you look up on how closures, prototypal inheritance, and several object design patterns (modules, etc.) work in JavaScript.

Ozrix
  • 3,489
  • 2
  • 17
  • 27
2

Both 1. and 2. are pretty much identical in your example. You could make 2. make an actual difference by declaring "private" variables in the IIFE's scope, like this:

var myObject2 = function () {
    var myPrivateProp = ...;
    return {
        getPrivateProp: function() { return myPrivateProp; }
    };
}();

In general, those create a value, not something that you would call a class of values.

Instead, what 3. and 4. are doing is creating a prototype that can be then used to create more usable values out of it. Whether you actually declare the defaults on the prototype or in the constructor doesn't make much difference.

So, to sum up, 1&2 are something like a "lambda" object, without a named prototype, while 3&4 actually make the thing reusable and recreatable.

Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135