0

Sorry I can't phrase this better. But I ran across some code like the following:

MyObject.prototype = Object.create(MyObject.prototype);
MyObject.prototype.constructor = MyObject;

And I just can't seem to figure out what it does. MyObject is defined above it something like this:

function MyObject(options) {
    this.someProp = someDefault;
    this.otherProp = process(options.something);
    // etc...
}

and it's always called as a constructor. I'm just wondering what benefit those first two lines provide and if it's a known pattern in Javascript.

Dan
  • 10,990
  • 7
  • 51
  • 80
  • 4
    Are you sure it should be `MyObject` on both sides of the assignment? – Evan Davis Aug 14 '13 at 19:55
  • 2
    This just adds one (useless) level of indirection to the prototype chain of MyObject instances... Where did you find that code? – bfavaretto Aug 14 '13 at 19:57
  • Seriously, why do people write JS like this? – Michael Benin Aug 14 '13 at 19:58
  • At the moment I'm not trying to pass any judgement here. I've been programming Javascript for years but am sorry to say I still don't deeply understand prototypes. Just trying to figure it out.. – Dan Aug 14 '13 at 20:05
  • And obviously `MyObject` isn't the real name. Code has been changed to protect the innocent and/or guilty. – Dan Aug 14 '13 at 20:06
  • 1
    Okay, but are you sure `MyObject.prototype = Object.create(MyObject.prototype);` isn't actually `MyObject.prototype = Object.create(MyOtherObject.prototype);`? – bfavaretto Aug 14 '13 at 20:07
  • @bfavaretto yes I'm sure. Other than obfuscating the name, those two lines are an exact copy. – Dan Aug 14 '13 at 20:08
  • @Dan it's not that I don't believe you, but... I don't believe you. – Evan Davis Aug 14 '13 at 20:25
  • @Dan those lines are meant to restore the `prototype` inherited for `MyObject` function to function normally as required because it probably has been modified. Check my answer below it explains in short snippets. – woofmeow Aug 14 '13 at 20:38

5 Answers5

2

I just can't seem to figure out what it does

It creates a new object that inherits from [the old] MyObject.prototype via Object.create and then overwrites MyObject.prototype with that. It also explicitly adds a .constructor property which actually should be existing already.

I'm just wondering what benefit those first two lines provide

None, unless before that snippet someone has corrupted the prototype (like MyObject.prototype = Object.prototype) and this is an attempt to fix it.

…and if it's a known pattern in Javascript.

Not like this. Using Object.create to set up the prototype chain for inheritance between constructor-defined "classes" is a known pattern, but then the constructors would be different on each side of the assignment.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

I really don't see any benefit in doing that.

What it's doing is providing the new object with the previous objects methods. But it's coming from the same object...

Here is a good example of JS inheritance:

http://jsfiddle.net/aDCmA/2/

var App = (function(){
    var Being = function() {
        this.living = true;
        this.breathes = function () {
            return true;
        };
    };

    var Robert = function() {
        this.blogs = true;
        this.getsBored = function () {
            return "You betcha";
        }
    };
    Robert.prototype = new Being();

    return {
        Being: Being,
        Robert: Robert,
        being: function(){ return new Being(); },
        robert: function(){ return new Robert(); }
    }
}());

Here is another question that is similar: inherit prototype methods from other classes without overriding own prototype methods

Credit to Robert Nyman for originally blogging about it: http://robertnyman.com/2008/10/06/javascript-inheritance-how-and-why/

Community
  • 1
  • 1
Michael Benin
  • 4,317
  • 2
  • 23
  • 15
  • 1
    `Robert.prototype = new Being();` is *not* a good example of inheritance. [What is the reason (not) to use the 'new' keyword here?](http://stackoverflow.com/q/12592913/1048572) – Bergi Aug 14 '13 at 20:13
  • Because then it overrides Beings methods if you decide to add to Robert's prototype. – Michael Benin Aug 14 '13 at 20:48
  • If you could provide a method, or link, of JS inheritance using prototype, I'm interested in better ways. Honestly these days at my job I'm never writing Vanilla JS and these questions/discussions are refreshing. – Michael Benin Aug 14 '13 at 21:00
  • @MichaelBenin In this answer http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 I've tried to cover the basics of JS constructor functions. – HMR Aug 15 '13 at 00:46
1

Let's see line by line:

MyObject.prototype = Object.create(MyObject.prototype);

This redefines MyObject.prototype to an object that inherits from MyObject.prototype. This is unusual, because it makes no sense to inherit from itself.

MyObject.prototype.constructor = MyObject;

Since the previous line overwrote MyObject.prototype, this is just fixing the constructor property that was lost in the process.

I can think of one scenario where tht might be useful: if some code before that messed up with MyObject.prototype, for example assigning the prototype of another constructor to it:

MyObject.prototype = SomethingElse.prototype; // wrong way to do inheritance.

Then the code you posted would be an attempt to fix it.

bfavaretto
  • 71,580
  • 16
  • 111
  • 150
1

The two lines of code provided seem to be an incorrect attempt of the use of prototypal inheritance, but I see where you're going with this and what you're trying to accomplish.

As we know, there are two ways in JavaScript to define objects that have properties and methods as members - the object literal notation and function notation. Using object literal notation, we don't have immediate access to the new keyword (think of this like using abstract classes in Java or C#). With function notation, we have access to the new keyword because the initial declaration of an object as a function serves as our constructor.

In ECMAScript 5, The Object object was given a method called create that provided developers a simple way to create a new object from an existing object declared with the object literal notation. (See documentation here). However, objects created in function notation have problems with this method because they are Function objects. The Object.create method is a great way to use simple inheritance, allowing access to the base properties and methods.

With function notation, once the new keyword is used, the result is not a function, but rather an object. For example, I can test this:

var Obj = function(){};
console.log(typeof Obj) // "function"

console.log(typeof new Object()); // "object"

Because of this, you can only inherit once (meaning the child object cannot be derived from):

var MyObject = new Object();
var anotherObj = new MyObject() // throws exception

To alleviate this problem, you need to follow three steps:

  1. Create your child object in function notation (so you can create new instances of it using the new keyword and inherit from it).
  2. Set the child object's prototype (an object) to the result of a new instance of the base object (which will be an object as well).
  3. Set the constructor of the child object (which happens to be on the object's prototype) back to reference the Function of itself (which is a function prior to instantiation). If you don't do this, the constructor will remain an object, which cannot spawn new instances.

From here, you can create new instances of both the child and parent objects and derive from both, using the pattern. Here's a practical example:

var Vehicle = function(){};
Vehicle.prototype.start = function() {
   return this.make + " " + this.model + " " + "started";
}

var Car = function(color, make, model) {
   this.color = color;
   this.make = make;
   this.model = model;
}
Car.prototype = new Vehicle();
Car.prototype.constructor = Car; 

var myCar = new Car("red", "chevy", "aveo");
myCar.start(); //"chevy aveo started"
James Lee Baker
  • 797
  • 6
  • 9
  • You could have used `Object.create` to set inheritence, it's used a lot for that. What if the Vehicle constructor expects parameters that are not known until you create a Car instance? `Car.prototype = Object.create(Vehicle.prototype);Car.prototype.constructor=Car;` – HMR Aug 15 '13 at 01:00
0

This is perfectly valid Javascript.

Any javascript function (say Func)can be used as a constructor and the constructor invocation also requires a prototype property (i.e. F.prototype or the prototype associated with the function) . Thus (almost) every function has a prototype property. The value of this property (i.e. Func.prototype).

Now the value of this prototype associated with the function is an object itself that has a single non enumerable property called constructor. And the value of this constructor property is the function object (i.e. F itself).

Lets take an example.

Say I construct a function Func

var Func = function() {
           //your definition
          };

Now since this can be invoked as a constructor it has to have a prototype property Func.prototype lets call this proto.

proto = Func.prototype;

Now the prototype has a single property (that is non enumerable) called constructor. This constructor has a value that is equal to the function object itself.

Dont believe me check it like this

Func.prototype.constructor === Func // =>true

Will always return true for any function.

Now from the code you explained : So basically these two lines

MyObject.prototype = Object.create(MyObject.prototype);
MyObject.prototype.constructor = MyObject;

are modifying the value of the prototye to have a constructor property with the value of MyObject that is defined. But that would have happened anyways in the normal course of things. But the reason could be that maybe the prototype of the object has been changed earlier from the class it has been inherited from. In that case would those two lines make sense.

Hope that helps :)

woofmeow
  • 2,370
  • 16
  • 13