I am concerned about the following code piece:
//subclass extends superclass
Rectangle.prototype = new Shape();
You should be, that's a common pattern, but not a very good one, because then you're using Shape both to create prototypes and to initialize instances. It should do one or the other. (Consider, for instance, what you'd do if you needed to give Shape arguments? What args would you use creating the Rectangle.prototype?)
But you don't want Rectangle.prototype = Shape.prototype either, because then you can't add things to Rectangle.prototype (since it's pointing at the same object Shape.prototype is pointing at, you'd add them to Shape instances as well).
So what we want is to create a new object that uses Shape.prototype as its prototype (e.g., that inherits from Shape.prototype) just like the objects created via new Shape do, but without calling Shape to create it; and then use that new object as Rectangle.prototype.
As of ECMAScript5, we can do that using Object.create:
Rectangle.prototype = Object.create(Shape.prototype);
Object.create creates a new object and assigns the first argument you give it as the object's underlying prototype.
Having done that, although it's not strictly necessary, we should also set the constructor property on our new object so that it refers to Rectangle:
Rectangle.prototype.constructor = Rectangle;
We do that because that way, the relationship between Rectangle.prototype and Rectangle looks the way §13.2 of the spec says it should look. Basically, if you have a constructor function X, then X.prototype.constructor should refer to X. Sometimes people rely on that for cloning operations and such (JavaScript itself does not rely on that — for instance, instanceof doesn't rely on it).
So we can use ES5's Object.create to do this. But even today, not all JavaScript engines support Object.create. So instead, we can do this indirectly, by creating a temporary constructor function, letting it borrow Shape.prototype as its prototype property, and then using that temporary constructor to create our new object to use as Rectangle.prototype:
function Ctor() { }
Ctor.prototype = Shape.prototype; // Borrow the prototype
Rectangle.prototype = new Ctor(); // Create the new object
...and again we should set the constructor property:
Rectangle.prototype.constructor = Rectangle;
Typically, rather than writing all that out each time, you use a helper like this:
function derive(Parent, Child) {
function Ctor() { this.constructor = Child; }
Ctor.prototype = Parent.prototype;
Child.prototype = new Ctor();
return Child; // For chaining
}
Then use it like this:
derive(Shape, Rectangle);
The end result of all this is that we only call Shape from within Rectangle, to initialize instances. We don't call it to create Rectangle.prototype.
If you're interested in inheritance plumbing in JavaScript, you might be interested in my Lineage script, which handles the above and a lot more besides. When I say "interested," I don't necessarily mean using it (although you're welcome to), but looking at the unminified source and at this page comparing Lineage with doing the same thing without a helper could give you an idea how this stuff works.