by Philipp MarkovicsJun 13 2019
Designer at Nextjournal

Inheritance in JavaScript & ClojureScript

ES 6

ES 6 brings the class keyword for defining classes. extends can be used to inherit parent properties and super for calling parent methods withing the child’s scope.

class CodeMirrorView {
  constructor (el, lang) {
    this.el = el;
    this.lang = lang;
    this.editor = new CodeMirror(el, { mode: lang });
  }
  update (node) {
    this.node = node;
    return true;
  }
}

class CodeListingView extends CodeMirrorView {
  constructor (el, lang) {
    super(el, lang);
    const header = document.createElement("header");
    this.el.appendChild(header);
  }
}
JavaScript

ES 5

To achieve the same effect in ES 5 we have to set the child’s prototype to the parent’s. Calling the child’s constructor will extend upon the parent’s prototype. To use parent methods, we will have to call them from the parent’s prototype and set the call scope explicitly to the current scope (this).

function CodeMirrorView(el, lang) {
  this.el = el;
  this.lang = lang;
  this.editor = new CodeMirror(el, { mode: lang });
}
CodeMirrorView.prototype.update = function(node) {
  this.node = node;
  return true;
}

function CodeListingView(el, lang) {
  CodeMirrorView.call(this, el, lang);
  const header = document.createElement("header");
  this.el.appendChild(header);
}

CodeListingView.prototype = Object.create(CodeMirrorView.prototype);
CodeListingView.constructor = CodeListingView;
JavaScript

ClojureScript

This mimics pretty much what’s going on in ES 5 because there are no macros for using the native ES 6 class, extends and super keywords. There is a discussion on the cljs JIRA regarding this.

(defn CodeMirrorView [el lang]
  (this-as this
    (set! (.-el this) el)
    (set! (.-lang this) lang)
    (set! (.-editor this) (js/CodeMirror. el #js {:mode lang}))))

(set! (.. CodeMirrorView -prototype -update)
      (fn [node]
        (this-as this
          (set! (.-node this) node))))

(defn CodeListingView [el lang]
  (this-as this
    (.call CodeMirrorView this el lang)
    (let [header (js/document.createElement "header")])
      (set! (.-header this) header)))

(set! (.. CodeListingView -prototype)
      (js/Object.create (.-prototype CodeMirrorView)))

(set! (.. CodeListingView -prototype -constructor)
      CodeListingView)
ClojureScript