Created
November 29, 2013 22:08
-
-
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)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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