A Touch of Class
Inheritance in JavaScript
MARK DALGLESH:
@markdalgleish
Engineer @ Aconex
Organiser @ MelbJS
JS looks like it has classes...
var charlie = new Actor();
But JS doesn't have classes???
function Actor(name) {
this.name = name;
}
Actor.prototype.act =
function(line) {
alert(line);
};
function SilentActor(name) { this.name = name; } SilentActor.prototype = new Actor(); SilentActor.prototype.canSpeak = false;
Let's travel to the year 1995...
"Java applets are the future"
-1995 dude
Mocha
became LiveScript
became JavaScript
Looks like Java. Tastes like Scheme mixed with Self.
Classical inheritance:
Class => Instance
Prototypal inheritance:
Object => Object
You must unlearn what you have learned.
ES5 Inheritance:
Object.create(parentObject);
var actor = { canAct: true }; var busterKeaton = Object.create(actor);
var actor = { canAct: true, canSpeak: true }; var silentActor = Object.create(actor); silentActor.canSpeak = false;
var busterKeaton = Object.create(silentActor);
busterKeaton.canAct?
Find first occurence of property (does it exist?)
-- busterKeaton? NO |-- silentActor? NO |-- actor? YES (true)
Differential inheritance
All silent actors lose their jobs?
silentActor.isEmployed = false; busterKeaton.isEmployed; // false
ES5 Prototype Reflection:
Object.getPrototypeOf(busterKeaton); // -> silentActor
"Where's super?"
Any function can run in any context
silentActor.act = function(line) { // Super: actor.act.call(this, line); }
"Where are my constructors?"
DIY Constructor:
function makeActor(name) { var a = Object.create(actor); a.name = name; return a; }
Understanding prototypes with a touch of class...
Let's revisit our simple example:
var charlie = new Actor();
"Actor" is just a regular function...
function Actor() {}
function Actor(name) { this.name = name; }
It's used as a constructor when invoked with "new"
Any function can
be used as a constructor...
"charlie" inherits from the object at "Actor.prototype"
var charlie = new Actor();
Yes, functions can have properties.
function Actor(){} // We can set any property: Actor.foo = 'bar'; Actor.abc = [1,2,3]; // Used for constructors: Actor.prototype = {foo: 'bar'};
Since any function
can be used as a constructor...
...all functions
have a "prototype" property
(just in case)
alert("is a function, so..."); typeof alert.prototype === 'object'; // true
"What about multiple inheritance?"
A function's prototype property inherit from another:
SilentActor.prototype = Object.create(Actor.prototype); // We can now augment the prototype: SilentActor.prototype .canSpeak = false;
Instantiating an object does 3 things...
var charlie = new Actor()
- Create new object (charlie) that inherits from object at Actor.prototype
- Run the "Actor" function against charlie
- Return charlie
Sound familiar?
function makeActor(name) { var a = Object.create(actor); a.name = name; return a; }
var busterKeaton = new SilentActor();
busterKeaton.canAct?
Find first occurence of property
(does it exist?)
-- busterKeaton? NO |-- SilentActor.prototype? NO |-- Actor.prototype? YES
Want class syntax today?
"Class",
"Klass",
etc.
var Actor = Class.extend({ init: function(name) { this.name = name; }, act: function(line) { alert(this.name + ': ' + line); } });
CoffeeScript has classes...
class SilentActor extends Actor canSpeak: false act: (line) -> alert("#{@name}: #{line}")
TypeScript has classes...
class SilentActor extends Actor { public canSpeak = false; public act(line: string) { alert(this.name + ': ' + line); } }
But it all boils down to prototypes
Want native class syntax?
The current ES6 draft has classes...
class SilentActor extends Actor { canSpeak = false; act(line) { alert(this.name + ': ' + line); } }