1

I am reading this piece of code

// Shape - superclass
function Shape() {
  this.x = 0;
  this.y = 0;
}

// superclass method
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved.');
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

rect instanceof Rectangle; // true
rect instanceof Shape; // true

rect.move(1, 1); // Outputs, 'Shape moved.'

I got really confused by this snippet

Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

Why don't we use Rectangle.prototype = Shape.prototype, anything special that Object.create() does? and what if Rectangle.prototype.constructor = Rectangle; is not called?

1
  • Why don't we use Rectangle.prototype = Shape.prototype A Rectangle is a Shape but not every Shape is a Rectangle. Changing Rectangle.prototype would change Shape.prototype. Constructor is repaired for consistency in case someone wants to use it (and console logging in Chrome). More on constructor, prototype, inheritance, mix ins and so on here: stackoverflow.com/a/16063711/1641941 Commented Dec 5, 2014 at 2:40

2 Answers 2

2

If you do Rectangle.prototype = Shape.prototype then any modification that you will perform on Rectangle.prototoype will reflect on Shape.prototype because they are the same object.

To avoid this, we create a new object that has it's prototype link pointing to Shape.prototype using Object.create(Shape.prototype).

As for Rectangle.prototype.constructor = Rectangle;, it's to make sure that new Shape().constructor points to Rectangle, not Shape.

The native prototype of a function has a constructor property that points to that function.

e.g.

function Rectangle() {}

Rectangle.prototype.constructor === Rectangle; //true

Now, when we do Rectangle.prototype = ..., we break that reference and need to fix it afterwards.

Sign up to request clarification or add additional context in comments.

2 Comments

Hi, thanks for your reply. yes.. I am always confused about under what circumstance a variable is a reference (as in this case Rectangle.prototype) and when it is a copy. do you have any insights on this or can you point me to some good articles?
@Blake Objects are referenced, but primitive values are copied (no choice because they are immutable).
0

If you’d just set Rectangle.prototype to Shape.prototype, then both Rectangle and Shape would share the same object as prototype. That would mean, that everything you add to Rectangle.prototype would also be available on Shape.prototypeRectangle would no longer inherit from Shape.

Object.create(parent) creates a child object that inherits from the parent object passed in. This way, all properties of the parent are also available to the child, while properties on the child don’t affect the parent.

To answer your question (“Why we need to define constructors in JavaScript?”) – we don’t need to. You could also just use plain objects:

// Shape - superclass
function Shape() {
  return {
    x: 0, 
    y: 0,
    // superclass method
    move: function(x, y) {
      this.x += x;
      this.y += y;
      console.info('Shape moved.');
    }
  };
}

// Rectangle - subclass
function Rectangle() {
  var rectangle = Shape();
  // rectangle-specific things could be added here
  return rectangle;
}

var rect = Rectangle();

rect instanceof Rectangle; // false, instanceof does not work here
rect instanceof Shape; // false

rect.move(1, 1); // Outputs, 'Shape moved.'

11 Comments

Your non-constructor sample is not so pure and quite misleading. Here's what you should be doing var shape = { ... }; var rectangle = Object.create(shape); //add rectangle stuff var r1 = Object.create(rectangle);
Please forgive me for writing examples that are not so pure. I just wanted to demonstrate that we’re not bound to “class-like” inheritance in JavaScript. Pureness is not my primary concern. I don’t agree that the example is misleading, though. Shape() returns a fresh shape on every call. Nothing is gained by inheriting from it with Object.create(). It’s entirely possible and safe to extend that object directly.
Well, it's misleading because there's a widespread naming convention which states that upper-cased functions should be constructors, but even if you do fix that, your code is still inefficient in terms of memory because you aren't sharing anything through prototypes. It's also inefficient in terms of execution e.g. you will have to mutate the newly created shape object everytime to create to rectangle instances. All these are solved by using Object.create like I suggested, which is the standard way of avoiding constructors.
You could share the methods by not creating new ones for every object, and rather just assigning methods by reference. I didn't do it to keep the example simple. This way, we would save memory by not allocating prototypes. Mutation: Calling super constructors on newly created instances also mutates them. The code is going through the same mutations each time, JITs optimize for this. Btw, using Object.create() here wouldn’t save any memory, since the example doesn't use prototypal inheritance. Object.create() does not have any benefit at all for my example.
I made no reference to constructor/initialization's mutation and that's unavoidable. What I'm saying is that with your implementation every new shape must be mutated to become a rectangle and that's unecessary. Yes, Object.create would save memory because the default values and functions wouldn't have to be copied for every instance. Just try both approaches and do a profiling, it will be obvious with multiple instances. Finally, some engines like V8 are optimizing expando properties set in constructors.
|

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.