Skip to content

Instantly share code, notes, and snippets.

@dplyukhin
Created November 29, 2013 22:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dplyukhin/7712643 to your computer and use it in GitHub Desktop.
Save dplyukhin/7712643 to your computer and use it in GitHub Desktop.
A comprehensive demo on Javascript inheritance (untested but it's probably right XD)
// object_1.foo === 'bar'
// object_1['foo'] === 'bar'
var object_1 = {
foo: 'bar'
}
// object_2 uses object_1 as its *prototype* - it inherits the properties but they are not its own
// object_2.hasOwnProperty('foo') === false
// object_2.foo === 'bar'
var object_2 = Object.create(object_1);
// Calling `new gen()` creates a new `this` object which is returned by default
// Omitting `new` sets `this` to be the enclosing scope (such as `window`) - WRONG FOR A CONSTRUCTOR
function gen() {
// A safe fix is to check if `new` was used, and if it wasn't we'll return a new object
if (!(this instanceof gen))
return new gen();
this.foo = 'bar';
// `obj = new gen()` implies `return this`
}
// Constructors can also add a prototype to the `this` object. All new gen objects will share this prototype object in common.
gen.prototype = { foobar: true };
// Or equivalently (this one will not override an existing prototype):
gen.prototype.foobar = true;
// Let's instantiate gen
var g = new gen();
// Because we added the fix, we can also do
var g = gen();
// But it's safer to use the `new` keyword, at least for clarity.
// The constructor gen() set foo for us
// g.hasOwnProperty('foo') === 'bar'
// The prototype set foobar for us
// g.foobar === true
// g.hasOwnProperty('foobar') === false
// We had to look down the prototype chain to find that
// Because g points to the gen.prototype object, changes propogate to all instances (wow!)
gen.prototype.foobar = false;
// g.foobar === false
var f = new gen();
// f.foobar === false;
// Changing direct properties will not propogate
g.foo = 'baz';
// f.foo === 'bar'
// Be careful - objects can be detatched from the prototype
g.foobar = 7;
gen.prototype.foobar = true;
// f.foobar === true
// g.foobar === 7
// g.foobar no longer points to the prototype object!
// Here's a simple extension function
function extend(obj, proto, deep) {
if (!proto) proto = {};
for (var prop in proto) {
// If it's already defined, skip setting
// If deep, then inherit every property in the proto chain TO THE SURFACE LEVEL OF obj (*not* a prototype)
if (obj[prop] === undefined && (deep || proto.hasOwnProperty(prop))) {
obj[prop] = proto[prop];
}
}
}
extend(g, {'a': 'letter'});
// g.hasOwnProperty(a) === true
var be_careful = {};
// Deep inheritance
extend(be_careful, f, true);
// be_careful.hasOwnProperty(foo) === true
// be_careful.hasOwnProperty(foobar) === true
// it didn't become a prototype!
// To inherit from an object as a prototype, do
var ok = Object.create(f);
// ok.hasOwnProperty(foo) === false
// ok.hasOwnProperty(foobar) === false
// ok.foo === 'bar'
// ok.foobar === true
// Note that this way does not do multiple inheritance, so think carefully about what you want to do
// Last but not least, we can do a pseudo-inheritance style in our constructors like this
function inherit(child, parent) {
extend(child.prototype, parent.prototype);
}
// Be careful here - make sure you define the child's prototype BEFORE inheriting, or this will override the inheritance
function ctorA() {
this.a = 'a';
// If we also want to inherit direct properties from gen, we can do
// gen.call(this)
// Which lets gen set some values onto `this` directly. Look up `function#call` on MDN for more info
}
ctorA.prototype = {
'prop': 8
}
inherit(ctorA, gen);
var inst = new ctorA();
// inst.a === 'a'
// inst.prop === 8
// inst.foobar === true
// inst.hasOwnProperty('foobar') === false
// inst.foo === undefined
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment