Skip to content

Instantly share code, notes, and snippets.

@reynaldot
Last active December 20, 2015 19:48
Show Gist options
  • Save reynaldot/6185394 to your computer and use it in GitHub Desktop.
Save reynaldot/6185394 to your computer and use it in GitHub Desktop.
Followup notes on javascript inheritance after reading some of Stoyan Stefanov's Javascript Patterns book.
var assert = require('assert');
/**
* Default pattern
*
* Inherits properties added to this and prototype
*/
// parent constructor:
function Parent(name) {
this.name = name || 'foo';
}
Parent.prototype.say = function() {
return this.name;
};
// empty child constructor:
function Child(name) {}
function inherit(C, P) {
C.prototype = new P();
}
inherit(Child, Parent);
var kid = new Child();
assert.equal(kid.say(), 'foo');
kid.name = 'bar';
assert.equal(kid.say(), 'bar');
delete kid.name;
assert.equal(kid.say(), 'foo');
var assert = require('assert');
/**
* Rent-a-constructor pattern
*
* Inherits properties added to this inside the parent constructor
* Does not inherit members added to the prototype.
*/
// parent constructor:
function Parent(name) {
this.name = name || 'foo';
}
Parent.prototype.say = function() {
return this.name;
};
// empty child constructor:
function Child() {
Parent.call(this);
}
var kid = new Child();
assert(kid.hasOwnProperty('name'));
assert.equal(kid.prototype, undefined);
kid.name = 'bar';
assert.equal(kid.name, 'bar');
delete kid.name;
assert.equal(kid.name, undefined);
var assert = require('assert');
/**
* Rent and set Prototype
*
* Copies the parent's own members and references to the parent's reusable functionality.
*/
// parent constructor:
function Parent(name) {
this.name = name || 'foo';
}
Parent.prototype.say = function() {
return this.name;
};
// empty child constructor:
function Child(name) {
Parent.apply(this, arguments);
}
Child.prototype = new Parent();
var kid = new Child();
assert.equal(kid.say(), 'foo');
kid.name = 'bar';
assert.equal(kid.say(), 'bar');
delete kid.name;
assert.equal(kid.say(), 'foo');
var assert = require('assert');
/**
* Share the Prototype
*
* All objects, including the parent, reference the same prototype.
* If a child modifies any of its prototype members, it will also modify its parent's.
*
* Children don't inherit the parent's properties.
*/
// parent constructor:
function Parent(name) {
this.name = name || 'foo';
}
Parent.prototype.say = function() {
return this.name;
};
// empty child constructor:
function Child(name) {}
function inherit(C, P) {
C.prototype = P.prototype;
}
inherit(Child, Parent);
var kid = new Child();
// Note how the prototype of an object is never made accessible.
assert.equal(kid.prototype, undefined);
// Also note the kid's own name property was not inherited.
assert.equal(kid.say(), undefined);
kid.name = 'bar';
assert.equal(kid.say(), 'bar');
// Now we proceed to screw up the parent's prototype method by modifying the children's
Child.prototype.say = function () {
return 'hello ' + this.name;
};
var father = new Parent();
assert.equal(father.say(), 'hello foo');
var assert = require('assert');
/**
* A Temporary Constuctor
*
* The parent's prototype members are inherited by the child using a proxy object.
* This patterns breaks the direct link between parent's and child's prototype.
*/
// parent constructor:
function Parent(name) {
this.name = name || 'foo';
}
Parent.prototype.say = function() {
return this.name;
};
// empty child constructor:
function Child(name) {}
function inherit(C, P) {
var F = function () {};
F.prototype = P.prototype;
C.prototype = new F();
}
var kid = new Child();
// No chance we can now screw the parent's prototype method:
Child.prototype.say = function () {
return 'hello ' + this.name;
};
var parent = new Parent();
assert.equal(parent.say(), 'foo');
var assert = require('assert');
/*
* Prototypal Inheritance - ECMAScript 5
*/
var parent = {
name: 'foo'
};
var kid = Object.create(parent);
assert.equal(kid.name, 'foo');
function Parent () {
this.name = 'foo';
}
Parent.prototype.say = function () {
return this.name;
};
// Inherit everything:
kid = Object.create(new Parent());
assert.equal(kid.say(), 'foo');
// Inherit only prototype members
kid = Object.create(Parent.prototype);
assert.equal(kid.say(), undefined);
// Inherit everything and override parent's property
kid = Object.create(new Parent(), {name: {value: 'bar'}});
assert.equal(kid.say(), 'bar');
var assert = require('assert');
/*
* Prototypal Inheritance
*
* No classes involved. Objects inherit from other objects.
*/
// Parent created with literal object
var parent = {
name: 'foo'
};
var object = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
var kid = object(parent);
assert.equal(kid.name, 'foo');
function Parent() {
this.name = 'foo';
}
// Parent created with a constructor function instead.
Parent.prototype.say = function () {
return this.name;
};
parent = new Parent();
kid = object(parent);
assert.equal(kid.say(), 'foo');
// Notice we could also inherit only the prototype methods
kid = object(Parent.prototype);
assert.equal(kid.say(), undefined);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment