Waldo CTO at QallOut CTO at Insight Replay Founder Over 40 NPM packages Contributor to major Node.js packages Avid OSS author Local Node.js Meetup organizer (Greece) founder organizer skgtech.io DEVit Conference Software Engineer, CTO, founder Recently moved to London from Greece Available for hire
cat = new Animal(); cat instanceof Animal; // true Forces use of a Constructor Uses the "new" keyword "instanceof" works Utilizes all the language features provided for inheritance
Ctor var Animal = function() {}; var Cat = function() { Animal.call(this); }; util.inherits(Cat, Animal); For ES5 Node.js Provides helpers built in the language (versions 6 and bellow)
the language's intended way for inheritance. Generally accepted as the way to do inheritance in Javascript. Signal / Noise ratio in JS land is a problem, stay confident & focused.
have a prototype Everything in JS is an Object The Prototype is the blueprint for creating objects and instances The Instances or Objects do not have a prototype Functions have a prototype var str = new String(); var bool = new Boolean(); var num = new Number();
objects and instances var Animal = function(name) { this.name = name; }; Animal.prototype.getName = function() { return this.name; }; var pony = new Animal('pony'); pony.getName(); // "pony" The instance Invokes the Constructor The Constructor Instance local variable A method
= function() {} fn.prototype // fn {} // -> constructor: function() // -> __proto__: Object All prototypes have at least two properties: constructor: A Function that gets invoked when constructing the instance __proto__: A reference to the parent prototype
= 'a string'; str.__proto__; // Outputs the Object that was used to construct // the "str" instance: // String {length: 0, [[PrimitiveValue]]: ""} All variables of any type in Javascript have the __proto__ property!
have the __proto__ property! Remember: __proto__ is a reference Points to the Object that constructed the instance Instances using the "new" keyword have a __proto__ that points to the Ctor
{}; TempCtor.prototype = ParentCtor.prototype; ChildCtor.prototype = new TempCtor(); }; ChildCtor.prototype.constructor = ChildCtor; Create a temporary Constructor to copy the Parent Prototype on.
{}; TempCtor.prototype = ParentCtor.prototype; ChildCtor.prototype = new TempCtor(); }; ChildCtor.prototype.constructor = ChildCtor; Instanciate the temporary Ctor and assign it by overwriting the Child's prototype. This is where inheritance happens.
{}; TempCtor.prototype = ParentCtor.prototype; ChildCtor.prototype = new TempCtor(); }; ChildCtor.prototype.constructor = ChildCtor; Let's break this out, too much happened here: "var inst = new TempCtor()" we created an instance The instance has a __proto__ referencing the TempCtor Which in our case is the Parent's Prototype.
{}; TempCtor.prototype = ParentCtor.prototype; ChildCtor.prototype = new TempCtor(); }; ChildCtor.prototype.constructor = ChildCtor; We overwrite the prototype's special property "constructor" Using the actual Child Ctor Remember, the Ctor is a function
{}; TempCtor.prototype = ParentCtor.prototype; ChildCtor.prototype = new TempCtor(); }; ChildCtor.prototype.constructor = ChildCtor; So essentially we discard the default Child's prototype Overwriting it with the instance of the Parent Ctor
ParentCtor.prototype; }; This isn't a "copy", this is "assignment by reference" Every change you perform on the Child's prototype will directly change the Parent's prototype, they are the same Why not:
accessible, and in what context it is being executed. In the case of an Instance, scope is critical in maintaining access to methods and local properties
= name; // this will fail this.on('some event', this.doSomething); // this is ok this.on('some event', this.doSomething.bind(this)); }; var animal = new Animal('cat'); // this will fail onEvent(animal.onEventHandler); // this is ok onEvent(animal.onEventHandler.bind(animal)); // With Arrow function onEvent(() => animal.onEventHandler);
color) { Animal.call(this, name); this.color = color; }; util.inherits(Cat, Animal); Cat.prototype.getColor = function() { return this.color; }; 1. First thing you do in your Ctor is to call your Parent's Ctor using your own, new, context (scope) 2. Then, right after the Ctor, invoke the inherits function 3. Afterwards define your methods. Can even overwrite the parent's 1 3 2
{ constructor (name, color) { super(name); this.color = color; } getColor() { return this.color; } } 1. First thing you do in your Ctor is to call your Parent's Ctor with super 2. Afterwards define your methods. Can even overwrite the parent's 1 2 From Node 8
childs the longer the chain gets Js will lookup serially for a method all the way up to the last prototype This can result in performance hits in some particular cases
{ // NEW SCOPE HERE, "this" REFERS TO // THIS FUNCTION'S CONTEXT cb(name); }); }; Use .bind(this) at end of the anonymous function expression used as a callback Use the Arrow Function Expression ( fat arrow => )
"Classes" because they do not behave like Classes They resemble a Class, thus the term "Classical Inheritance" But in reality, this is "Prototypical Inheritance" We signify a Ctor by capitalizing the first letter var Animal = function() {}
the instance Asynchronous operations in Ctors are forbidden! Define any and all properties in the constructor Use null to initialize properties with no value Never return any value from the Ctor It will screw up everything var Animal = function() { this.name = null; this.color = null; }
the Ctor directly, that is considered a Static function and will not be inherited var Animal = function() { this.name = null; this.color = null; } Animal.staticFn = function() { // Will not be inherited };