Monday, July 27, 2015

Objects linked to other objects - Simplifies so much

I recently made my first npm module (babel-plugin-proto-to-create), but this just stems from my general frustration with class-based OO. Not saying it's a terrible thing at all, or that I can't understand it at all, but there's nothing simpler than objects linked to other objects. Nothing more elegant than this:


const Vehicle = {
  new(make, model) {
    return {
      __proto__: this,
      make, model,
    }
  },

  toString() {
    return [
      "Type:  " + this.type,
      "Make:  " + this.make,
      "Model: " + this.model,
    ].join("\n")
  },
}

const Car = {
  __proto__: Vehicle,

  type: "Car",
}

const Truck = {
  __proto__: Vehicle,

  type: "Truck",
}

Merely creating an instance is as simple as this:


let car = Car.new("Nissan", "Ultima")

I really love the simplicity of this, pure prototypal OO. It's simple, concise, and beautiful. Or, if you'd prefer, you could always use ES6 classes:



class Vehicle {
  constructor(make, model) {
    this.make = make
    this.model = model
  }

  toString() {
    return [
      "Type:  " + this.type,
      "Make:  " + this.make,
      "Model: " + this.model,
    ].join("\n")
  }
}

class Car extends Vehicle {
  constructor(...args) {
    super(...args)
    this.type = "Car"
  }
}


class Truck extends Vehicle {
  constructor(...args) {
    super(...args)
    this.type = "Truch"
  }
}

Lot more boilerplate. Extending mixins in ES6 classes are also a little more complicated:


function mixin(Class, ...srcs) {
  class C extends Class {}
  Object.assign(C.prototype, ...srcs)
  return C
}

class Foo extends mixin(Bar, Baz) {}

// Or, if you want to mixin classes...

function mixin(Class, ...others) {
  class C extends Class {}
  Object.assign(C.prototype, ...others.map(D => D.prototype))
  return C
}

class Foo extends mixin(Bar, Baz) {}

Why do classes, even JS prototypal-based classes, have to be so complicated?



function mixin(Type, ...others) {
  return Object.assign({__proto__: Type}, ...others)
}

const Foo = {
  __proto__: mixin(Bar, Baz),
}

And with ES7's object spread, the mixin picture is only going to make this nicer:


const Type = {
  __proto__: Foo,
  ...Mixin1,
  ...Mixin2,

  method() {},
}

Very lightweight mixins that don't need any syntactical support. Not to mention you could even define these is-a/has-a relationships conditionally at object creation time:


const Type = {
  new(condition) {
    return {
      __proto__: this,
      ...(condition ? Mixin1 : Mixin2),
    }
  }
}

I know of no other language with this kind of flexibility.

No comments:

Post a Comment