Slide 1

Slide 1 text

Classical Inheritance Classical Inheritance in Javascript in Javascript

Slide 2

Slide 2 text

Inheritance in Javascript Inheritance in Javascript Lots of ways It's complicated We'll talk about Classical / Prototypical

Slide 3

Slide 3 text

Why Classical / Why Classical / Prototypical? Prototypical?

Slide 4

Slide 4 text

Why Classical / Prototypical? var Animal = function() {}; var 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

Slide 5

Slide 5 text

Why Classical / Prototypical? var util = requite('util'); // Parent Ctor var Animal = function() {}; var Cat = function() { Animal.call(this); }; util.inherits(Cat, Animal); Node.js Provides helpers built in the language

Slide 6

Slide 6 text

Why Classical / Prototypical? It really has the most widespread usage in the wild.

Slide 7

Slide 7 text

How to Inherit How to Inherit var util = require('util'); // Parent Ctor var Animal = function() {}; var Cat = function() { Animal.call(this); }; util.inherits(Cat, Animal); Node.js

Slide 8

Slide 8 text

How to Inherit How to Inherit var inherits = function(ChildCtor, ParentCtor) { function TempCtor() {}; TempCtor.prototype = ParentCtor.prototype; ChildCtor.prototype = new TempCtor(); ChildCtor.prototype.constructor = ChildCtor; }; // Parent Ctor var Animal = function() {}; var Cat = function() { Animal.call(this); }; inherits(Cat, Animal); Vanilla Javascript ES3

Slide 9

Slide 9 text

How to Inherit How to Inherit var inherits = function(ChildCtor, ParentCtor) { function TempCtor() {}; TempCtor.prototype = ParentCtor.prototype; ChildCtor.prototype = new TempCtor(); ChildCtor.prototype.constructor = ChildCtor; }; // Parent Ctor var Animal = function() {}; var Cat = function() { Animal.call(this); }; inherits(Cat, Animal); Vanilla Javascript ES3 WTF¿??!¡¿

Slide 10

Slide 10 text

How to Inherit How to Inherit var inherits = function(ChildCtor, ParentCtor) { ChildCtor.prototype = Object.create(ParentCtor.prototype); ChildCtor.prototype.constructor = ParentCtor; }; // Parent Ctor var Animal = function() {}; var Cat = function() { Animal.call(this); }; inherits(Cat, Animal); Vanilla Javascript ES5

Slide 11

Slide 11 text

How to Inherit How to Inherit var inherits = function(ChildCtor, ParentCtor) { ChildCtor.prototype = Object.create(ParentCtor.prototype); ChildCtor.prototype.constructor = ParentCtor; }; // Parent Ctor var Animal = function() {}; var Cat = function() { Animal.call(this); }; inherits(Cat, Animal); Vanilla Javascript ES5 meh...

Slide 12

Slide 12 text

How to Inherit How to Inherit // Parent Ctor class AnimalES6 { constructor(name) { this.name = name; } } class Cat extends AnimalES6 { constructor(color) { this.color = color; super('cat'); //call the parent method with super } } Vanilla Javascript ES6

Slide 13

Slide 13 text

How to Inherit How to Inherit // Parent Ctor class AnimalES6 { constructor(name) { this.name = name; } } class Cat extends AnimalES6 { constructor(color) { this.color = color; super('cat'); //call the parent method with super } } Vanilla Javascript ES6 COOL! ... but it's sugar

Slide 14

Slide 14 text

What did just What did just happen? happen? ... lets talk about the ... lets talk about the prototype prototype

Slide 15

Slide 15 text

The Javascript Prototype The Javascript Prototype Javascript is a prototypical language All Objects 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();

Slide 16

Slide 16 text

The Javascript Prototype The Javascript Prototype The Prototype is the blueprint for creating 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

Slide 17

Slide 17 text

The Javascript Prototype The Javascript Prototype Going down the rabbit hole... var fn = 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

Slide 18

Slide 18 text

The Javascript Prototype The Javascript Prototype Going downer the rabbit hole... var str = '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!

Slide 19

Slide 19 text

The Javascript Prototype The Javascript Prototype All variables of any type in Javascript have the __proto__ property! Remember! 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

Slide 20

Slide 20 text

So WTF inheritance? So WTF inheritance? var inherits = function(ChildCtor, ParentCtor) { function TempCtor() {}; TempCtor.prototype = ParentCtor.prototype; ChildCtor.prototype = new TempCtor(); ChildCtor.prototype.constructor = ChildCtor; };

Slide 21

Slide 21 text

So WTF inheritance? So WTF inheritance? var inherits = function(ChildCtor, ParentCtor) { function TempCtor() {}; TempCtor.prototype = ParentCtor.prototype; ChildCtor.prototype = new TempCtor(); }; ChildCtor.prototype.constructor = ChildCtor; Create a temporary Constructor to copy the Parent Prototype on.

Slide 22

Slide 22 text

So WTF inheritance? So WTF inheritance? var inherits = function(ChildCtor, ParentCtor) { function TempCtor() {}; TempCtor.prototype = ParentCtor.prototype; ChildCtor.prototype = new TempCtor(); }; ChildCtor.prototype.constructor = ChildCtor; Copy the Parent's Prototype to the temporary Constructor's prototype

Slide 23

Slide 23 text

So WTF inheritance? So WTF inheritance? var inherits = function(ChildCtor, ParentCtor) { function TempCtor() {}; 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.

Slide 24

Slide 24 text

So WTF inheritance? So WTF inheritance? var inherits = function(ChildCtor, ParentCtor) { function TempCtor() {}; 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.

Slide 25

Slide 25 text

So WTF inheritance? So WTF inheritance? var inherits = function(ChildCtor, ParentCtor) { function TempCtor() {}; 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

Slide 26

Slide 26 text

So WTF inheritance? So WTF inheritance? var inherits = function(ChildCtor, ParentCtor) { function TempCtor() {}; 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

Slide 27

Slide 27 text

We are not finished We are not finished yet! yet!

Slide 28

Slide 28 text

The Inheritance The Inheritance var util = require('util'); var Animal = function(name) { this.name = name; }; Animal.prototype.getName = function() { return this.name; }; // Inherits from Animal var Cat = function(name, color) { Animal.call(this, name); this.color = color; }; util.inherits(Cat, Animal); Cat.prototype.getColor = function() { return this.color; }; That's the key Part right there!

Slide 29

Slide 29 text

The Inheritance The Inheritance So... So... We copied the Parent's prototype to the Child... ... now we need to make sure that all the Constructors from our Parents will be invoked! ... in the right Scope!

Slide 30

Slide 30 text

The Inheritance The Inheritance The Scope.... The Scope....

Slide 31

Slide 31 text

The Scope The Scope 99% of your problems will be cause of Scope SO PAY SO PAY ATTENTION ATTENTION

Slide 32

Slide 32 text

The Scope The Scope Scope refers to where variables and functions are 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

Slide 33

Slide 33 text

The Scope The Scope Base Definition var Animal = function(name) { this.name = name; }; Animal.prototype.getName = function() { return this.name; };

Slide 34

Slide 34 text

The Scope The Scope Retains Scope - Vanilla var animal = new Animal('cat'); animal.getName(); // "cat" Looses Scope var animal = new Animal('cat'); var getName = animal.getName; getName(); // undefined Retains Scope - bind var animal = new Animal('cat'); var getName = animal.getName.bind(animal); getName(); // "cat"

Slide 35

Slide 35 text

The Scope The Scope Retains Scope - call var animal = new Animal('cat'); var getName = animal.getName; getName.call(animal); // "cat" Retains Scope - apply var animal = new Animal('cat'); var getName = animal.getName; getName.apply(animal); // "cat"

Slide 36

Slide 36 text

The Scope The Scope In Practice... var Animal = function(name) { this.name = 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 $('body').on('load', animal.onLoad); // this is ok $('body').on('load', animal.onLoad.bind(animal));

Slide 37

Slide 37 text

So, back to So, back to inheritance inheritance

Slide 38

Slide 38 text

Inheritance Ctor Inheritance Ctor // Inherits from Animal var Cat = function(name, 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 we define our own methods and can even overwrite the parent's 1 3 2

Slide 39

Slide 39 text

The Prototype Chain The Prototype Chain

Slide 40

Slide 40 text

The Prototype Chain The Prototype Chain The more you extend a Ctor creating 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

Slide 41

Slide 41 text

Common Gotchas Common Gotchas Only define methods on the prototype Everything else on the Ctor var Animal = function(name) { this.name = name; }; // Never do this Animal.prototype.name = ''; Animal.prototype.getName = function() { return this.name; }; var cat = new Animal('cat'); var dog = new Animal('dog'); cat.getName(); // "dog"

Slide 42

Slide 42 text

Common Gotchas Common Gotchas Never invoke the inheritance method after your methods var util = require('util'); var Animal = function(name) { this.name = name; }; // Inherits from Animal var Cat = function(name, color) { Animal.call(this, name); this.color = color; }; Cat.prototype.getColor = function() { return this.color; }; // Will overwrite and DELETE getColor() util.inherits(Cat, Animal);

Slide 43

Slide 43 text

Common Gotchas Common Gotchas ... and of course The Scope

Slide 44

Slide 44 text

Common Gotchas Common Gotchas Scope on methods Animal.prototype.getName = function(cb) { this.db.getName(function(name) { // NEW SCOPE HERE, "this" REFERS TO // THIS FUNCTION'S CONTEXT cb(name); }); };

Slide 45

Slide 45 text

Common Gotchas Common Gotchas Scope on methods Animal.prototype.getName = function(cb) { if (this.name) { cb(this.name); } else { var self = this; this.db.getName(function(name) { self.name = name; cb(name); }); } };

Slide 46

Slide 46 text

Rules & Best Practises Rules & Best Practises We call Constructors "Constructors" and not "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() {}

Slide 47

Slide 47 text

Rules & Best Practises Rules & Best Practises Use the constructor strictly to construct the instance Asynchronous operations 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; }

Slide 48

Slide 48 text

Rules & Best Practises Rules & Best Practises You may define a method on 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 };

Slide 49

Slide 49 text

Shameless Plug Shameless Plug Time Time

Slide 50

Slide 50 text

CIP CIP Classical Inheritance Classical Inheritance Pattern Pattern an NPM module

Slide 51

Slide 51 text

npm install cip thanpolas/cip How to install How to install CIP CIP

Slide 52

Slide 52 text

Simple Interface Simple Interface CIP CIP var cip = require('cip'); var Child = cip.extend(); var GrandChild = Child.extend();

Slide 53

Slide 53 text

The Constructor The Constructor CIP CIP var cip = require('cip'); var Animal = cip.extend(function(name) { this.name = name; }); var Cat = Animal.extend(function(color) { this.color = color; this.name = 'cat'; }); var gilly = new Cat('black'); gilly instanceof Animal; // true

Slide 54

Slide 54 text

Singleton Pattern Singleton Pattern CIP CIP var cip = require('cip'); var Animal = cip.extend(function(name) { this.name = name; }); var Cat = Animal.extendSingleton(function() { this.name = 'cat'; }); var theCat = Cat.getInstance(); var anotherCat = new Cat(); theCat === anotherCat; // true

Slide 55

Slide 55 text

Mixins Mixins CIP CIP var cip = require('cip'); var Behavior = cip.extend(function() { this.mood = 'awesome'; }); var Animal = cip.extend(function(name) { this.name = name; }); cip.mixin(Animal, Behavior); var cat = new Animal('cat'); cat.mood; // 'awesome'

Slide 56

Slide 56 text

Casting Casting CIP CIP // Use EventEmitter as the base Constructor. var EventEmitter = require('events').EventEmitter; var cip = require('cip'); var CeventEmitter = cip.cast(EventEmitter); var Thing = CeventEmitter.extend(); var newThing = new Thing(); newThing instanceof CeventEmitter; // true newThing instanceof EventEmitter; // true newThing.on('nextThing', doSomething);

Slide 57

Slide 57 text

Thank you Thanasis Polychronakis @thanpolas https://speakerdeck.com/thanpolas

Slide 58

Slide 58 text

Questions Thanasis Polychronakis @thanpolas https://speakerdeck.com/thanpolas ¿ ¿