Past, Present and Future of
Inheritance in JavaScript

By @ralphholzmann @rlph

Ralph Holzmann

Babbys

babbys

Inheritance in JavaScript

Prototypal Inheritance

WAT

Things to know before continuing

How does it work?

How does it work? (Continued)

Crotchford on Prototypal Inheritance

WAT
“Prototypal inheritance is more powerful than classical inheritance, because prototypal inheritance can emulate classical inheritance, but classical inhertiance cannot emulate prototypal inheritance.”

Classical vs Prototypal

Java JavaScript
Strongly-typed Loosely-typed
Static Dynamic
Classical Prototypal
Classes Functions
Constructors Functions
Methods Functions
// Parent Constructor
function Parent (first, last) {
  this.first = first;
  this.last  = last;
}

Parent.prototype.getFullName = function () {
  return this.first + " " + this.last;
}

var me = new Parent("Ralph", "Holzmann");
me.getFullName(); // "Ralph Holzmann"

// Child Constructor
function Child (first) {
  this.constructor = Child;
  this.first = first;
}

Child.prototype = me;

var jack = new Child("Jack");
jack.getFullName(); // "Jack Holzmann"

Pseudo-Classical Inheritance

The Past

// Base Constructor
function Model (id, attributes) {
  this.id = id;
  this.attributes = attributes;
}
Model.prototype.save = function () {
  var json = JSON.stringify( this.attributes );
  var name = this.constructor.name.toLowerCase();
  localStorage.setItem( name + this.id, json );
}

// User Constructor
function User (id, attributes) {
  this.constructor = User;
  Model.call(this, id, attributes); // "super"
}
User.prototype = new Model(null)
User.prototype.save = function() {
  $.post("/save", JSON.stringify( this.attributes ));
  Model.prototype.save.call(this); // "super"
}

Things to note

Enter Abstractions…

Enter Abstractions…

  • Dean Edward's
  • var object = new Base();
    
    object.extend({
      helloWorldText: "Hello World!",
      sayHelloWorld: function () {
        console.log( this.helloWorldText );
      }
    });
    
    object.sayHelloWorld(); // "Hello World!" 

    Present - ES5 and Abstractions

    var Person = Class.extend({
      init: function(isDancing){
        this.dancing = isDancing;
      }
    });
    var Ninja = Person.extend({
      init: function(){
        this._super( false );
      }
    });
    
    var p = new Person(true);
    p.dancing; // => true
    
    var n = new Ninja();
    n.dancing; // => false

    The Present

    Object.create

    var a = {a: 1}; 
    // a → Object.prototype → null
     
    var b = Object.create(a);
    // b → a → Object.prototype → null
    console.log(b.a); // 1 (inherited)
     
    var c = Object.create(b);
    // c → b → a → Object.prototype → null

    Object.create Shim

    if (!Object.create) {
        Object.create = function (o) {
            function F() {}
            F.prototype = o;
            return new F();
        };
    }

    Newer Abstractions…

    var ObjectClass = Backbone.Model.extend({
    
      helloWorldText: "Hello World!",
    
      sayHelloWorld: function () {
        console.log( this.helloWorldText );
      }
    
    });
    
    var object = new ObjectClass();
    
    object.sayHelloWorld(); // "Hello World!"

    Newer Abstractions…

    var ObjectClass = can.Construct({
    
      helloWorldText: "Hello World!",
    
      sayHelloWorld: function () {
        console.log( this.helloWorldText );
      }
    
    });
    
    var object = new ObjectClass();
    
    object.sayHelloWorld(); // "Hello World!"

    Transpilers

    ES6 Classes

    The Future

    ES6 Classes

    class Model {
      constructor( id, attributes ) {
        this.id = id;
        this.attributes = attributes;
      }
      save() {
        var json = JSON.stringify( this.attributes );
        window.localStorage.setItem( this.id, json );
      }
    }
    
    class User extends Model {
      save() {
        $.post("/save", JSON.stringify( this.attributes ));
        super();
      }
    }
    var ralph = new User(1, { name: "Ralph" });

    Bonus! Mixin's

    // Vanilla implementation
    function Model( id, attributes ) { /* … */ }
    
    function EventEmitterMixin() {
      this.emit = function( event, data ) { /* … */ }
      this.on = function( event, callback ) { /* … */ }
      this.off = function( event, callback ) { /* … */ }
    }
    
    function User() {
      Model.call(this)
      EventEmitterMixin.call(this)
    }
    User.prototype = new Model(null);
    
    var ralph = new User(0, { name: "Ralph Holzmann" });
    ralph.emit("name", ralph.name);
    

    Bonus! Mixin's

    //Library implementation
    var EventEmitterMixin = {
      emit: function( event, data ) { /* … */ },
      on: function( event, callback ) { /* … */ }
      off: function( event, callback ) { /* … */ }
    };
    
    function User() {
      Model.call(this);
      $.extend(this, EventEmitterMixin);
    }
    User.prototype = new Model();
    
    var ralph = new User(0, { name: "Ralph Holzmann" });
    ralph.emit("name", ralph.name);
    
    

    Reach Out!