Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JavaScript inheritance: beyond the basics

JavaScript inheritance: beyond the basics

Slides of my talk at JSConf EU 2012
Video: https://www.youtube.com/watch?v=NyClWddeO_A

Axel Rauschmayer

October 06, 2012
Tweet

More Decks by Axel Rauschmayer

Other Decks in Programming

Transcript

  1. [ ] inheritance obj-exempl classes super proto What you will

    learn function Employee(name, title) { Person.call(this, name); this.title = title; } Employee.prototype = Object.create(Person.prototype); Employee.prototype.constructor = Employee; Employee.prototype.describe = function () { return Person.prototype.describe.call(this) + " (" + this.title + ")"; } We can do better: Object-based library (no functions!) for ECMAScript 5. Classes (and more) for ECMAScript 6. Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 2 / 42
  2. [inheritance] obj-exempl classes super proto JavaScript inheritance Class-based languages: instance-of

    relationship (between classes and instances) subclass-of relationship (between classes) JavaScript: Only has-prototype relationship (between objects) Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 4 / 42
  3. [inheritance] obj-exempl classes super proto Constructor aPerson is an instance

    of Person. Person Person.prototype prototype constructor aPerson [[Prototype]] Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 5 / 42
  4. [inheritance] obj-exempl classes super proto Subtyping Employee is a sub-constructor

    of Person. Employee Employee.prototype prototype constructor anEmployee [[Prototype]] Person Person.prototype prototype constructor [[Prototype]] calls Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 6 / 42
  5. inheritance [obj-exempl] classes super proto Exemplars How to call “object

    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
  6. inheritance [obj-exempl] classes super proto Function exemplar versus object exemplar

    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
  7. inheritance [obj-exempl] classes super proto Function exemplars: constructor versus prototype

    Roles: Constructor C: instantiate. C.prototype: everything else. Operations: Check: instance-of x instanceof C === C.prototype.isPrototypeOf(x) Subtyping Sub.prototype = Object.create(Super.prototype) Check: subtype-of Super.prototype.isPrototypeOf(Sub.prototype) Super-call Super.prototype.foo.call(this) Generic methods Array.prototype.slice.call(arguments) Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 10 / 42
  8. inheritance [obj-exempl] classes super proto Function exemplars: constructor versus prototype

    Roles: Constructor C: instantiate C.prototype: everything else Operations: Check: instance-of x instanceof C === C.prototype.isPrototypeOf(x) Subtyping Sub.prototype = Object.create(Super.prototype) Check: subtype-of Super.prototype.isPrototypeOf(Sub.prototype) Super-call Super.prototype.foo.call(this) Generic methods Array.prototype.slice.call(arguments) Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 11 / 42
  9. inheritance [obj-exempl] classes super proto Omitting the constructors Employee Employee.prototype

    prototype constructor anEmployee [[Prototype]] Person Person.prototype prototype constructor [[Prototype]] Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 12 / 42
  10. inheritance [obj-exempl] classes super proto "CTO" title "Jane" name [[Prototype]]

    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
  11. inheritance [obj-exempl] classes super proto Proto.js, a micro-framework for object

    exemplars var Person = Proto.extend({ constructor: function (name) { this.name = name; }, describe: function() { return "Person called "+this.name; } }); var Employee = Person.extend({ constructor: function (name, title) { Employee.super.constructor.call(this, name); this.title = title; }, describe: function () { return ( Employee.super.describe.call(this) + " (" + this.title + ")" ); } }); Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 14 / 42
  12. inheritance [obj-exempl] classes super proto var jane = Employee.new("Jane", "CTO");

    // 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
  13. inheritance [obj-exempl] classes super proto Implementing object exemplars How many

    lines of code? Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 16 / 42
  14. inheritance [obj-exempl] classes super proto Proto.js: the code var Proto

    = { 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
  15. inheritance obj-exempl [classes] super proto ECMAScript 6 classes Syntactic sugar

    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
  16. inheritance obj-exempl [classes] super proto class Person { constructor(name) {

    this.name = name; } describe() { return "Person called "+this.name; } } class Employee extends Person { constructor(name, title) { super(name); // super.constructor(name) this.title = title; } describe() { return super() + " (" + this.title + ")"; } } Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 20 / 42
  17. inheritance obj-exempl [classes] super proto class Person { constructor(name) {

    this.name = name; } describe() { return "Person called "+this.name; } } function Person(name) { this.name = name; } Person.prototype.describe = function () { return "Person called "+this.name; }; Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 21 / 42
  18. inheritance obj-exempl [classes] super proto class Employee extends Person {

    constructor(name, title) { super(name); this.title = title; } describe() { return super() + " (" + this.title + ")"; } } function Employee(name, title) { Person.call(this, name); this.title = title; } Employee.prototype = Object.create(Person.prototype); Employee.prototype.constructor = Employee; Employee.prototype.describe = function () { return Person.prototype.describe.call(this) + " (" + this.title + ")"; } Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 22 / 42
  19. inheritance obj-exempl classes [super] proto Super-references Refer to super-properties: super.prop

    super["prop"] Call super-methods: super.method(...) super(...) Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 24 / 42
  20. inheritance obj-exempl classes [super] proto Super-calls super.method(...) in current JavaScript:

    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
  21. inheritance obj-exempl classes [super] proto SuperConstructor.prototype.method.call(this, ...) "CTO" title "Jane"

    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
  22. inheritance obj-exempl classes [super] proto Semantics super.foo(x, y) is equivalent

    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
  23. inheritance obj-exempl classes super [proto] Special property __proto__ Pronounce: “dunder

    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
  24. inheritance obj-exempl classes super [proto] Use case: get the prototype

    Without __proto__: > Object.getPrototypeOf({}) === Object.prototype true With __proto__: > {}.__proto__ === Object.prototype true Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 30 / 42
  25. inheritance obj-exempl classes super [proto] Use case: create an object

    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
  26. inheritance obj-exempl classes super [proto] Use case: subtyping arrays Problem:

    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
  27. inheritance obj-exempl classes super [proto] Test: is __proto__ supported? Object.getPrototypeOf({

    __proto__: null }) === null Dr. Axel Rauschmayer (rauschma.de) JS inheritance: beyond the basics 2012-10-06 33 / 42
  28. inheritance obj-exempl classes super [proto] Caveat: objects as maps from

    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
  29. inheritance obj-exempl classes super [proto] __proto__ in ECMAScript 6 ECMAScript

    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
  30. inheritance obj-exempl classes super proto [ ] Take-aways Core of

    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
  31. inheritance obj-exempl classes super proto [ ] Thank you! Blog:

    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
  32. inheritance obj-exempl classes super proto [ ] Material Various: Drafts

    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
  33. inheritance obj-exempl classes super proto [ ] From object literals

    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
  34. inheritance obj-exempl classes super proto [ ] Person Person.prototype prototype

    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