2

How can I make or simulate a javascript class that extends another class and Array. I have another class Serializable that it also needs to extend to have a serialize and deserialize function.

class ArrayLikeClass extends Serializable({"_title": "raw"}){
  constructor(title){
    this._title = title;
  }
  /* Serializable adds these:
  serialize(){...serializes the class}
  static deserialize(){...deserializes the class}
  // I don't want to add these in manually */
}

Using this I have a class that is serializable. How can I make this have the methods serialize and deserialize from Serializable but also extend Array

I would use mixins as suggested in the possible duplicate, however how can I use mixins to have a static function deserialize

5
  • 2
    Serializable should be an interface, not a base class. In JavaScript "interfaces" are implemented through a common practice called "mixins", which should be a good google search term to use in finding a solution. Commented Apr 30, 2018 at 18:46
  • @PatrickRoberts How can I use mixins to make a static method Commented Apr 30, 2018 at 18:48
  • Possible duplicate of Multiple inheritance/prototypes in JavaScript Commented Apr 30, 2018 at 18:48
  • @pfg export default Serializable({_title:"raw"}, class extends Array { … }). Commented Apr 30, 2018 at 18:50
  • @pfg class ArrayLikeClass extends Array { ... } and ArrayLikeClass.deserialize = Serializable({_title: "raw"}).deserialize or something like that. Commented Apr 30, 2018 at 18:50

2 Answers 2

2

In JavaScript, classes are expressions. You can take advantage of this:

function addSerialize(superclass) {
  return class Serialize extends superclass {
    // serialize class goes here
  }
}

class MyArray extends addSerialize(Array) {
  // MyArray stuff goes here
}

AFAIK, Justin Fagani at Google came up with this approach. He also wrote a little helper library to assist with implementing it.

Sign up to request clarification or add additional context in comments.

12 Comments

Is there a way to not provide a superclass using a method like this? I assume extending undefined would throw an error. Edit: going to default superclass to an empty class, this should work
I like how this mixin approach mimics multiple inheritance by inserting an extra prototype in between with the interface implementation. +1
@pfg of course, just pass it an empty class: const Serialize = addSerialize(class {});. Again, classes in ES 6 JavaScript are first-class: you can assign them to vars, pass them as parameters, return them from functions, etc.
@pfg the core issue you're experiencing is that multiple inheritance is not supported in JavaScript, since inheritance is prototype-based. This is honestly a very elegant way of working around that issue, and while there are other approaches, this seems like the most DRY way you're going to get for what you're trying to do.
The only downside of this is that you'll need more code, specifically implementing Symbol.hasInstance in order to support a semantic instanceof operator that pretends there's multiple inheritance going on.
|
2

If you want to support instanceof operator, here's an extension to Jared's approach that allows this by defining Symbol.hasInstance memoizing Serializable():

function serialize () {
  // implementation
}

function deserialize (string) {
  // implementation
}

// optional memoization
const Bases = new WeakMap()

// use Object instead of anonymous class {} so that default can be memoized
function Serializable (Base = Object) {
  // optional memoization
  if (Bases.has(Base)) {
    return Bases.get(Base)
  }

  class Serialize extends Base {
    static deserialize () {}
    serialize () {}
  }

  Serialize.deserialize = deserialize
  Serialize.prototype.serialize = serialize

  // optional memoization
  Bases.set(Base, Serialize)

  return Serialize
}

// usage
class ArrayLike extends Serializable(Array) { }

let arrayLike = new ArrayLike()
console.log(arrayLike instanceof Array) // true
console.log(arrayLike instanceof Serializable(Array)) // true

1 Comment

Nice. Love the use of Object as the default.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.