npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@weddell/mixwith

v0.1.5

Published

A simple, powerful mixin applier for JavaScript classes

Downloads

2

Readme

mixwith.js

A simple and powerful mixin library for ES6.

mixwith differs from other mixin approaches because it does not copy properties from one object to another. Instead, mixwith works with "subclass factories" which create a new class that extends a superclass with the mixin - this is called a mixin application.

Example

my-mixin.js:

let MyMixin = (superclass) => class extends superclass {
  // mixin methods here
};

my-class.js

class MyClass extends MyMixin(MySuperClass) {
  // class methods here, go ahead, use super!
}

mixwith.js Helpers and Decorators

The subclass factory pattern does not require any support from a library. It's just a natural use of JavaScript class expressions. mixwith.js provides a few helpers that make mixins a little more powerful and easier to use.

mixwith.js makes some use cases very easy:

  • Determine if an object or class has had a particular mixin applied to it.
  • Cache mixin applications so that a mixin repeatedly applied to the same superclass reuses its resulting subclass.
  • De-duplicate mixin application so that including a mixin multiple times in a class hierarchy only applies it once to the prototype type chain.
  • Add instanceof support to a mixin function.

mix().with()

mixwith.js also provides a little bit of sugar with the mix() function that makes applying mixins read a little more naturally:

class MyClass extends mix(MySuperClass).with(MyMixin, OtherMixin) {
  // class methods here, go ahead, use super!
}

Advantages of subclass factories over typical JavaScript mixins

Subclass factory style mixins preserve the object-oriented inheritance properties that classes provide, like method overriding and super calls, while letting you compose classes out of mixins without being constrained to a single inheritance hierarchy, and without monkey-patching or copying.

Method overriding that just works

Methods in subclasses can naturally override methods in the mixin or superclass, and mixins override methods in the superclass. This means that precedence is preserved - the order is: subclass -> mixin__1 -> ... -> mixin__N -> superclass.

super works

Subclasses and mixins can use super normally, as defined in standard Javascript, and without needing the mixin library to do special chaining of functions.

Mixins can have constructors

Since super() works, mixins can define constructors. Combined with ES6 rest arguments and the spread operator, mixins can have generic constructors that work with any super constructor by passing along all arguments.

Prototypes and instances are not mutated

Typical JavaScript mixins usually used to either mutate each instance as created, which can be bad for performance and maintainability, or modify a prototype, which means every object inheriting from that prototype gets the mixin. Subclass factories don't mutate objects, they define new classes to subclass, leaving the original superclass intact.

Usage

Defining Mixins

The Mixin decorator function wraps a plain subclass factory to add deduplication, caching and instanceof support:

let MyMixin = Mixin((superclass) => class extends superclass {

  constructor(args...) {
    // mixins should either 1) not define a constructor, 2) require a specific
    // constructor signature, or 3) pass along all arguments.
    super(...args);
  }

  foo() {
    console.log('foo from MyMixin');
    // this will call superclass.foo()
    super.foo();
  }

});

Mixins defined with the mixwith.js decorators do not require any helpers to use, they still work like plain subclass factories.

Using Mixins

Classes use mixins in their extends clause. Classes that use mixins can define and override constructors and methods as usual.

class MyClass extends mix(MySuperClass).with(MyMixin) {

  constructor(a, b) {
    super(a, b); // calls MyMixin(a, b)
  }

  foo() {
    console.log('foo from MyClass');
    super.foo(); // calls MyMixin.foo()
  }

}

API Documentation

apply(superclass, mixin) ⇒ function

Applies mixin to superclass.

apply stores a reference from the mixin application to the unwrapped mixin to make isApplicationOf and hasMixin work.

This function is usefull for mixin wrappers that want to automatically enable hasMixin support.

Kind: global function
Returns: function - A subclass of superclass produced by mixin

| Param | Type | Description | | --- | --- | --- | | superclass | function | A class or constructor function | | mixin | MixinFunction | The mixin to apply |

Example

const Applier = (mixin) => wrap(mixin, (superclass) => apply(superclass, mixin));

// M now works with `hasMixin` and `isApplicationOf`
const M = Applier((superclass) => class extends superclass {});

class C extends M(Object) {}
let i = new C();
hasMixin(i, M); // true

isApplicationOf(proto, mixin) ⇒ boolean

Returns true iff proto is a prototype created by the application of mixin to a superclass.

isApplicationOf works by checking that proto has a reference to mixin as created by apply.

Kind: global function
Returns: boolean - whether proto is a prototype created by the application of mixin to a superclass

| Param | Type | Description | | --- | --- | --- | | proto | Object | A prototype object created by apply. | | mixin | MixinFunction | A mixin function used with apply. |

hasMixin(o, mixin) ⇒ boolean

Returns true iff o has an application of mixin on its prototype chain.

Kind: global function
Returns: boolean - whether o has an application of mixin on its prototype chain

| Param | Type | Description | | --- | --- | --- | | o | Object | An object | | mixin | MixinFunction | A mixin applied with apply |

wrap(mixin, wrapper) ⇒ MixinFunction

Sets up the function mixin to be wrapped by the function wrapper, while allowing properties on mixin to be available via wrapper, and allowing wrapper to be unwrapped to get to the original function.

wrap does two things:

  1. Sets the prototype of mixin to wrapper so that properties set on mixin inherited by wrapper.
  2. Sets a special property on mixin that points back to mixin so that it can be retreived from wrapper

Kind: global function
Returns: MixinFunction - wrapper

| Param | Type | Description | | --- | --- | --- | | mixin | MixinFunction | A mixin function | | wrapper | MixinFunction | A function that wraps mixin |

unwrap(wrapper) ⇒ MixinFunction

Unwraps the function wrapper to return the original function wrapped by one or more calls to wrap. Returns wrapper if it's not a wrapped function.

Kind: global function
Returns: MixinFunction - The originally wrapped mixin

| Param | Type | Description | | --- | --- | --- | | wrapper | MixinFunction | A wrapped mixin produced by wrap |

Cached(mixin) ⇒ MixinFunction

Decorates mixin so that it caches its applications. When applied multiple times to the same superclass, mixin will only create one subclass, memoize it and return it for each application.

Note: If mixin somehow stores properties its classes constructor (static properties), or on its classes prototype, it will be shared across all applications of mixin to a super class. It's reccomended that mixin only access instance state.

Kind: global function
Returns: MixinFunction - a new mixin function

| Param | Type | Description | | --- | --- | --- | | mixin | MixinFunction | The mixin to wrap with caching behavior |

DeDupe(mixin) ⇒ MixinFunction

Decorates mixin so that it only applies if it's not already on the prototype chain.

Kind: global function
Returns: MixinFunction - a new mixin function

| Param | Type | Description | | --- | --- | --- | | mixin | MixinFunction | The mixin to wrap with deduplication behavior |

HasInstance(mixin) ⇒ MixinFunction

Adds [Symbol.hasInstance] (ES2015 custom instanceof support) to mixin.

Kind: global function
Returns: MixinFunction - the given mixin function

| Param | Type | Description | | --- | --- | --- | | mixin | MixinFunction | The mixin to add [Symbol.hasInstance] to |

BareMixin(mixin) ⇒ MixinFunction

A basic mixin decorator that applies the mixin with apply so that it can be used with isApplicationOf, hasMixin and the other mixin decorator functions.

Kind: global function
Returns: MixinFunction - a new mixin function

| Param | Type | Description | | --- | --- | --- | | mixin | MixinFunction | The mixin to wrap |

Mixin(mixin) ⇒ MixinFunction

Decorates a mixin function to add deduplication, application caching and instanceof support.

Kind: global function
Returns: MixinFunction - a new mixin function

| Param | Type | Description | | --- | --- | --- | | mixin | MixinFunction | The mixin to wrap |

mix([superclass]) ⇒ MixinBuilder

A fluent interface to apply a list of mixins to a superclass.

class X extends mix(Object).with(A, B, C) {}

The mixins are applied in order to the superclass, so the prototype chain will be: X->C'->B'->A'->Object.

This is purely a convenience function. The above example is equivalent to:

class X extends C(B(A(Object))) {}

Kind: global function

| Param | Type | Default | | --- | --- | --- | | [superclass] | function | Object |

MixinFunction ⇒ function

A function that returns a subclass of its argument.

Kind: global typedef
Returns: function - A subclass of superclass

| Param | Type | | --- | --- | | superclass | function |

Example

const M = (superclass) => class extends superclass {
  getMessage() {
    return "Hello";
  }
}