of Person. Person Person.prototype prototype constructor aPerson [[Prototype]] Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 5 / 42
factories” (implementations of types) in JavaScript? Not a good choice: classes Allen Wirfs-Brock: exemplars. Function exemplars: constructors (factory is a function) Object exemplars: e.g. via Object.create() Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 8 / 42
Function exemplar: function Person(name) { this.name = name; } Person.prototype.describe = function () { return "Person called " + this.name; } var joe = new Person("Jane"); Object exemplar (to be improved later): var joe = Object.create(Person.prototype); joe.constructor("Jane"); Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 9 / 42
function() {...} describe constructor function() {...} [[Prototype]] [[Prototype]] describe function() {...} constructor function() {...} jane Employee Person [[Prototype]] new function() {...} extend function() {...} Proto Type (meta-)methods Proto.new, Proto.extend ⇒ automatically inherited by Person and Employee Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 13 / 42
// new > Employee.isPrototypeOf(jane) // instanceof true > jane.describe() 'Person called Jane (CTO)' Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 15 / 42
= { extend: function (subProps) { // Only on this slide: non-standard __proto__ var subProto = subProp.__proto__ = this; subProto.super = this; // for super-references return subProto; }, new: function () { var instance = Object.create(this); if (instance.constructor) { instance.constructor.apply(instance, arguments); } return instance; }, }; Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 17 / 42
for constructor functions Benefits: ease of use increased compatibility between frameworks tool support foundation for future extensions (e.g. mixins) Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 19 / 42
SuperConstructor.prototype.method.call(this, ...) Three steps: 1 SuperConstructor.prototype: start the search for the super-method here. 2 method: find property method in that object or its prototypes. 3 call(this, ...): invoke the method with the current this. Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 25 / 42
name [[Prototype]] function() {... super ...} describe constructor function() {... super ...} [[Prototype]] [[Prototype]] describe function() {...} constructor function() {...} ... this jane Employee Person home Two crucial values: home (step 1, static), this (step 3, dynamic). Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 26 / 42
to home.[[Prototype]].foo.call(this, x, y) Internal properties of methods that become local variables: [[HomeObject]] (home) [[MethodName]]: enables super() (unqualified super-call) super is only allowed in classes in ES6, but works in any proto chain. Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 27 / 42
proto” (from “double underscore”) Non-standard in ECMAScript 5, part of ES6 First in Firefox, then pressure to add elsewhere Support: SpiderMonkey (Firefox), V8 (Chrome, Node.js), Nitro (Safari) Get and set the prototype of an object Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 29 / 42
with a given prototype Without __proto__ (alternative: property descriptors in 2nd arg): var obj = Object.create(myProto); obj.foo = 123; obj.bar = "abc"; With __proto__: var obj = { __proto__: myProto, foo: 123, bar: "abc" }; Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 31 / 42
instance is special (update length if elements are added). var MyArrayProto = Object.create(Array.prototype); MyArrayProto.foo = function (/*...*/) { /*...*/ }; function createMyArray() { var arr = Array.prototype.slice.call(arguments); arr.__proto__ = MyArrayProto; return arr; } Interaction: > var myarr = createMyArray(); > myarr[0] = 123; > myarr.length 1 Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 32 / 42
strings to values You have to be careful about what keys you use: > var obj = {}; > obj['first'] = 'Jane'; // OK > obj['last'] = 'Doe'; // OK > obj['__proto__'] = 123; // not OK Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 34 / 42
6 will include __proto__ Use as getter Object literal + __proto__ = “nicer” Object.create() Possibly: use as setter. Support for subtyping built-ins might be enough (e.g. Array.create()) Can be switched off (for some objects, possibly for all objects) Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 35 / 42
JavaScript inheritance is simple: objects + has-prototype relationship Object exemplars: not for the mainstream, but instructive User-friendliness in ECMAScript 6: classes, super, __proto__ Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 37 / 42
http://www.2ality.com/ Upcoming book on JavaScript (free online + O’Reilly): http://jsguide.org Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 38 / 42
of the ECMAScript 6 specification Proto.js: https://github.com/rauschma/proto-js Blog posts: “Prototypes as classes – an introduction to JavaScript inheritance” “What’s up with the ‘constructor’ property in JavaScript?” “What object is not an instance of Object?” “ECMAScript.next: classes” “A closer look at super-references in JavaScript and ECMAScript.next” “JavaScript: __proto__” Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 39 / 42
to constructors Problem: object exemplars not backward compatible. Alternative? var Person = defclass({ constructor: function (name) { this.name = name; }, describe: function () { return "Person called " + this.name; } }); Person Person.prototype prototype constructor Start here End up here Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 41 / 42
constructor in out function defclass(proto) { var constr = proto.constructor; constr.prototype = proto; return constr; } Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 42 / 42