0

reading the What techniques can be used to define a class in JavaScript, and what are their trade-offs? on stackoverflow i understand that i can define a class via

Method 1:

function Person(name, gender){
   this.name = name;
   this.gender = gender;
}

and add functions in prototype so as to avoid member functions recreated every time its instantiated. like

Person.prototype.speak = function(){
   alert("my name is" + this.name);
}

and create its instances via

var person = new Person("Bob", "M"); 

I think the creation of same object is possible with out new keyword like

Method 2:

var Person = function (name, gender) {

    return {name:name, gender:gender}; 

}

person  = Person("Bob", "M");

Is the second method doing exactly the same thing done by the first one? Also if so how would i mock up addition of functions via prototype (as we see in method 1's speak) in the second approach?

4 Answers 4

5

No, Method 2 != Method 1. The second method is creating a new anonymous object with a prototype that points at Object.prototype while the first is creating a new object with a prototype that points at Person.prototype.

In psuedo-code:

// Method #1
function Person(name, gender) {
    // The magic JS does *for us* (but *only* when invoked with `new`)
    var this = {};
    // __proto__ is the *internal* prototype reference
    // It's not required to be accessible unless you're in an ES6 environment.
    this.__proto__ = Person.prototype;

    // Person.prototype is also created by JS for us
    // and provided with a reference (among other things)
    // to this function as prototype.constructor.

    // Our stuff
    this.name = name;
    this.gender = gender;

    // More JS magic
    return this;
}

// Method #2
function Person(name, gender) {
    // Just our stuff - no magic JS goodness here
    return {
        name: name, gender: gender
    };
}
Sign up to request clarification or add additional context in comments.

3 Comments

JS doesn't do var this = {}; this.prototype = Person.prototype; this.constructor = Person;. That's totally wrong. Instead it does var this = Object.create(Person.prototype);. I'll remove the downvote when you correct your mistake. Also the prototype of the second object (the literal object) points to Object.prototype, and not Object.
@AaditMShah - good points, both :-) I've updated my answer to correct the mistake and to make it clear that it's the internal prototype property that's being set (not a necessarily accessible property named prototype). Thanks!
@SeanVieira No problem. I removed the downvote. BTW the constructor property is not set on the instance. It's inherited from the prototype.
3

As Sean Vieira explained the first method is not the same as the second method. In the first method the instance inherits from Person.prototype. In the second method the instance inherits directly from Object.prototype.

Method 1:

        null
         ^
         |
         | __proto__
         |
+------------------+
| Object.prototype |
+------------------+
         ^
         |
         | __proto__
         |
+------------------+
| Person.prototype |
+------------------+
         ^
         |
         | __proto__
         |
+------------------+
|      person      |
+------------------+

Method 2:

        null
         ^
         |
         | __proto__
         |
+------------------+
| Object.prototype |
+------------------+
         ^
         |
         | __proto__
         |
+------------------+
|      person      |
+------------------+

Interestingly the above diagrams show you that objects inherit from other objects in JavaScript, and not from constructors. Hence when you create new Person the instance inherits from Person.prototype, not from Person itself.

How is this relevant information? For starters it demonstrates that you don't need to create a constructor to creates instances of an object. Instead you directly create the prototype object as follows:

var person = {
    create: function (name, gender) {
        var person = Object.create(this);
        person.gender = gender;
        person.name = name;
        return person;
    },
    speak: function () {
        alert("My name is " + this.name + ".");
    }
};

In the above example person is equivalent to Person.prototype. You may now create an instance of person as follows:

var bob = person.create("Bob", "M");

The prototype chain of bob will look like this:

        null
         ^
         |
         | __proto__
         |
+------------------+
| Object.prototype |
+------------------+
         ^
         |
         | __proto__
         |
+------------------+
|      person      |
+------------------+
         ^
         |
         | __proto__
         |
+------------------+
|       bob        |
+------------------+

So why should you create objects like this instead?

  1. It looks cleaner. Everything is encapsulated in a single object literal.
  2. It's easier to understand that objects inherit from objects. No constructors needed.
  3. You don't need to use new to create an instance. This solves a lot of problems.

For more information about this pattern read my blog post on "Why Prototypal Inheritance Matters".

5 Comments

Interesting blog, I'm curious if you could explain the 3 reasons why prototypal patterns are better than constructor functions: 1: Is technically possible but you don't like the syntax (cleared up in comments). 2. Same as 1, don't like the syntax and prone to make mistakes. 3. Don't like the syntax, too confusing (same as 1 and 2). What I am missing is technical foundation as being better extendable or will perform better. To some point I agree that constructor functions could be error prone but even before using closure compiler I hardly ever misuse them (forgetting new)
@HMR I already answered the advantages of prototypal inheritance over classical in the following answer: stackoverflow.com/a/16872315/783743. Nevertheless I must admit that both these patterns are equivalent in power and choosing between one of them is just a matter of preference. However you should note that new is much faster than Object.create. Hence if you want performance then stick with new. I've created a small, fast library which makes working with constructors and prototypes much easier (especially for those who don't understand it): github.com/javascript/augment
Thank you for your reply, maybe this is an interesting read for you. Michael Bolin has worked on the closure compiler and defends the constructor function over functional pattern It's an old one and doesn't mention Object.create (prototypal pattern?) bolinfest.com/javascript/inheritance.php At some point JavaScript will have classes (Ecma 6)
+1 for prototypal but I'm not sure it's the same as the OP's method 2 as that looks like the functional pattern.
@HMR No. Crockford's functional pattern is definitely not the same as my prototypal pattern. The difference is that the functional pattern doesn't have inheritance in the form of delegation. Instead it extends a single object with new properties. What Crockford does is similar to what this answer does: stackoverflow.com/a/17008693/783743 It satisfies Liskov's substitution principle. Google.
0

Your examples are achieving the same thing with regards to accessing the properties, but they are not identical as the first method has the basic Object prototype. The answer to your second question is:

function Person( name, gender ){
   return {
     name: name,
     gender: gender,
     speak: function(){
        alert("my name is" + this.name);
     }
   };
}

Here there is no prototype. The function is baked into the object literal. The only value in using a literal instead of a prototype would be to create a closure so you can have private variables e.g:

function Person( name, gender ){
   return {
     speak: function(){
        alert("my name is" + name);
     }
   };
}

3 Comments

they're not equivalent - in method 2, person instanceof Person === false
i believe what you are suggesting is similar to this.speak = function() {..} not in protype..
@Alnitak Fair point. I suppose 'equivalent' !== 'doing the same thing', depending on what you need it to do.
0

Maybe this answer can explain a bit more about constructor functions, inheritance, private variables and overriding methods: Prototypical inheritance - writing up

The other answers already address your question; creating an object as an object literal {prop:val,method:function(){}} and creating an object using constructor functions: var MyObject=function(){this.prop=val};MyObject.prototype.method=function(){};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.