简体   繁体   中英

what is an elegant mixin/composition syntax for ES6 classes?

I'm looking for a clean and simple way to mixin methods to different classes. Most of the examples I've been able to find use the JS prototype , like this

Example code:

const _ = require("underscore")

let actions = {
  speak() {
    console.log(this.name + " animal speak")
  },

  look() {
    console.log(this.name + " animal looks")
  }
}

class Dog {
  constructor(name) {
    console.log("new Dog", name)
    this.name = name

    // modify instance and return
    let that = _.extend(this, actions)
    return that
  }

  speak() {
    console.log(this.name + " dog speaks")
  }

  bark() {
    console.log(this.name + " dog barks")
  }

}

function test() {
  let rover = new Dog("rover")

  // speak in "actions" overrides Dog.speak method
  rover.speak() // => rover animal speak

  // runtime works but ts-lint doesn't like it
  // look property doesn't exist on type 'dog'
  rover.look() // => rover animal looks

  // from dog since the method doesn't exist on actions
  rover.bark() // => rover dog barks
}

test()

So to use the prototype I could modify the above as:

Object.assign(Dog.prototype, actions)

and then just use a vanilla constructor that returns the this

class Dog {

  constructor(name) {
    this.name = name
  }
...
}

Object.assign(Dog.prototype, actions)

In both cases the mixin speak method will replace the Dog Class speak method, ok.

So my question is: if there is any other simpler/cleaner method to mixin methods across Classes?

And is there anything wrong with the above in terms of adding to a prototype? Is that creating copies of the actual methods? If it's only in the prototype and not every instance, I guess it's OK, but not entirely clear of any memory implications there.

As an alternative to using mixins you can use inheritance using extends to override methods on a class.

The disadvantage of inheritance compared to mixins is you can only extend one class at a time, but you can use multiple mixins. So it depends on what your use case is for which one you use.

Here is an example:

 class Animal { constructor(name) { console.log("new", this.constructor.name, name) this.name = name } speak() { console.log(this.name + " animal speak") } look() { console.log(this.name + " animal looks") } } class Dog extends Animal { constructor(name) { super(name) } speak() { console.log(this.name + " dog speaks") } bark() { console.log(this.name + " dog barks") } } const dog = new Dog('Fred') // Will call the overridden speak method on Dog dog.speak() // Fred dog speaks // Will call look on Animal as it hasn't been overriden in Dog dog.look() // Fred animal looks 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM