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);
}
}