Skip to content

Instantly share code, notes, and snippets.

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 gryzzly/3902289 to your computer and use it in GitHub Desktop.
Save gryzzly/3902289 to your computer and use it in GitHub Desktop.
How JavaScript OOP works
// constructor definition
var Foo = function() {
// when invoked with `new` it's as if the following implicitly happens
// this = { constructor: Foo };
// return this;
};
// For every function, `prototype` property is created automatically:
Foo.hasOwnProperty('prototype') // true
// This `prototype property` is an object, that holds any methods
// and properties which will be accessible to any objects created
// when the original [constructor] function will be invoked with
// `new` operator. We can modify it to extend functionality of future
// instances
Foo.prototype.log = function (message) { console.log(message); };
// create new instance with 'new'
var x = new Foo();
x.log('whoa') // logs 'whoa' to console
// create new instance without 'new'
// Above is almost equivalent to
var y = {};
// illustration purposes only. __proto__ should not be accessed directly
y.__proto__ = Foo.prototype;
y.constructor = Foo;
// So now:
x.constructor === y.constructor // true
x instanceof Foo // true
y instanceof Foo // true
// How does inheritance work
var Bar = function () {
// inherit instance properties
// `call(context)` invokes a function with context of `this`
// set to given parameter object
Foo.call(this);
};
// Set up prototype chain
//
// What we need to do is to have Foo.prototype object
// referenced as `__proto__` property of Bar.prototype
//
// This is how property look up works in JavaScript:
// you are accessing a property "baz" on object "fee" (`fee.baz`).
//
// JavaScript engine is looking for a property to be available directly
// on the object `fee`. If it doen't find such property, it goes up the
// prototype chain, by following the reference set as `__proto__` property
// of object `fee`.
//
// Best example will be any kind of object. Let's say we use object
// literal to create new object:
//
// var obj = {};
// // immediately we will have all `Object.prototype` methods available
// obj.hasOwnProperty === Object.prototype.hasOwnProperty // true
// // this means internal `__proto__` property is automatically
// // set to point at `Object.prototype`
// // And same goes for arrays:
// var data = [];
// // they have access to all `Array.prototype` properties
// data.push === Array.prototype.push // true
// // but also to all `Object.prototype` properties
// data.hasOwnProperty === Object.prototype.hasOwnProperty // true
//
// Note: if new prototype or object itself creates a property with the same name
// as one already defined somewhere in prototype chain, it is called "to shadow"
// previously defined property. The original property may be still accessed by directly
// referring to a method, supplying it with the right context to be executed upon:
//
// `Array.prototype.push.call(this)`
//
// Let's look at the mechanics that will allow us to setup inheritance
// with JavaScript custom types
//
var ProtoCarrier = function () {};
ProtoCarrier.prototype = Foo.prototype;
Bar.prototype = new ProtoCarrier;
Bar.prototype.constructor = Bar;
// is equivalent to
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.constructor = Bar;
// and also equivalent to
Bar.prototype.__proto__ = Foo.prototype;
// The final result will be that
(new Bar()) instanceof Foo // true
Foo.prototype.isPrototypeOf(new Bar()) // true
// And all methods and properties defined on `Foo.prototype` will
// be accessible for instances of `Bar`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment