GithubHelp home page GithubHelp logo

rudolf / stampit Goto Github PK

View Code? Open in Web Editor NEW

This project forked from stampit-org/stampit

0.0 3.0 0.0 613 KB

OOP is better with stamps: Composable object factories.

Home Page: http://pjabook.com

License: MIT License

JavaScript 100.00%

stampit's Introduction

stampit

----- [![Travis-CI](https://travis-ci.org/stampit-org/stampit.svg)](https://travis-ci.org/stampit-org/stampit)[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/stampit-org/stampit?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

Create objects from reusable, composable behaviors. Stampit uses three different kinds of prototypal OO to let you inherit behavior in a way that is much more powerful and flexible than classical OO.

Stampit was written as an example for the book, "Programming JavaScript Applications" (O'Reilly).

Looking for a deep dive into prototypal OO, stamps, and the Two Pillars of JavaScript? Learn JavaScript with Eric Elliott.

React Users. Stampit loves React. Check out react-stampit for composable components.

Status

  • v1, stable, in production use with millions of monthly users. There will be no breaking changes in the 1.x line.
  • v2, current stable. See breaking changes and new features on the releases page.

Install

Stampit can be installed via npm

npm install stampit

or Bower (UMD)

bower install stampit

or the unofficial gem

gem install stampitjs-rails

or referenced via CDNJS

or by downloading the latest release.

Examples

See API.

Features

  • Create factory functions (called stamps) which stamp out new objects. All of the new objects inherit all of the prescribed behavior.

  • Assign properties by passing a references object to the stamp (factory function).

  • Compose stamps together to create new stamps.

  • Inherit methods and default state.

  • Supports composable private state and privileged methods.

  • References are copied across for each instance.

  • Properties are deeply merged and cloned for each instance, so it won't be accidentally shared.

  • Initializers are called for each new instance. Provides wide extensibility to stamp behavior.

  • For the curious - it's great for learning about prototypal OO. It mixes three major types of prototypes:

    1. differential inheritance, aka delegation (for methods),
    2. cloning, aka concatenation/exemplar prototypes (for state),
    3. functional / closure inheritance (for privacy / encapsulation)

What is a Stamp?

A stamp is a composable factory function. Stamps allow you to inherit easily from multiple ancestors by composing multiple source stamps. You can combine properties, methods, and initializers (with closures) from any number of stamps to produce a new stamp. Stamps are more flexible than traditional factory functions or classical multiple inheritance. Traditional factory functions can't be composed together to produce new factory functions. Class inheritance does not provide a standardized mechanism for class composition.

Stamp composition takes advantage of three different kinds of prototypal inheritance:

  • Differential inheritance, aka delegation (e.g., JavaScript's [[Prototype]]),
  • Mixins/cloning with optional deep merge, aka concatenative inheritance (e.g., JavaScript's Object.assign()),
  • Functional / closure inheritance (for initialization or privacy/encapsulation)

When invoked the stamp factory function creates and returns object instances assigning:

const DbAuthStamp = stampit().
  methods({ authorize: function(){} }). // methods each new object instance will have
  refs({user: {name: 'guest', pwd: ''}}). // properties to be set by reference to object instances
  init(function(context){ }). // init function(s) to be called when an object instance is created
  props({db: {host: 'localhost'}}). // properties to be deeply merged to object instances
  compose(AnyOtherStamps); // mixes the stamp prototypes (methods, refs, init, etc.) together

const dbAuthorizer = DbAuthStamp({ user: adminUserCredentials });

How are Stamps Different from Classes?

  • It's easy to combine multiple stamps to create a new stamp with all of the source stamp capabilities
  • Stamps are factory functions, so they don't need to be invoked with new (which couples callers to the implementation of object instantiation)
  • Stamps don't create parent-child class hierarchies. Class hierarchies create "is-a" relationships between classes. Stamp composition creates "has-a" or "uses-a" relationships, instead. For that reason, stamp inheritance is less brittle than class inheritance.

What's the Point?

Prototypal OO is great, and JavaScript's capabilities give us some really powerful tools to explore it, but it could be easier to use.

Basic questions like "how do I inherit privileged methods and private data?" and "what are some good alternatives to inheritance hierarchies?" are stumpers for many JavaScript users.

Let's answer both of these questions at the same time. First, we'll use a closure to create data privacy:

const a = stampit().init(function () {
  const priv = 'a';
  this.getA = () => {
    return priv;
  };
});

It uses function scope to encapsulate private data. Note that the getter must be defined inside the function in order to access the closure variables.

Let's see if that worked:

a(); // Object -- so far so good.
a().getA(); // "a"

Yes. Got it. In both of these instances, we actually created a brand new object, and then immediately threw it away, because we didn't assign it to anything. Don't worry about that.

Here's another:

const b = stampit().init(function () {
  const priv = 'b';
  this.getB = () => {
    return priv;
  };
});

Those priv's are not a typo. The point is to demonstrate that a and b's private variables won't clash.

But here's the real treat:

const c = stampit.compose(a, b);

const foo = c(); // we won't throw this one away...

foo.getA(); // "a"
foo.getB(); // "b"

WAT? Yeah. You just inherited privileged methods and private data from two sources at the same time.

But that's boring. Let's see what else is on tap:

// Some more privileged methods, with some private data.
const availability = stampit().init(() => {
  var isOpen = false; // private

  instance.open = function open() {
    isOpen = true;
    return this;
  };
  instance.close = function close() {
    isOpen = false;
    return this;
  };
  instance.isOpen = function isOpenMethod() {
    return isOpen;
  }
});

// Here's a stamp with public methods, and some state:
const membership = stampit({
  methods: {
    add(member) {
      this.members[member.name] = member;
      return this;
    },
    getMember(name) {
      return this.members[name];
    }
  },
  refs: {
    members: {}
  }
});

// Let's set some defaults:
const defaults = stampit().refs({
  name: 'The Saloon',
  specials: 'Whisky, Gin, Tequila'
});

// Classical inheritance has nothing on this. No parent/child coupling. No deep inheritance hierarchies.
// Just good, clean code reusability.
const bar = stampit.compose(defaults, availability, membership);

// Note that you can override references on instantiation:
const myBar = bar({name: 'Moe\'s'});

// Silly, but proves that everything is as it should be.
myBar.add({name: 'Homer'}).open().getMember('Homer');

For more examples see the API and the advanced examples.

stampit's People

Contributors

angryobject avatar arikon avatar delapouite avatar ericelliott avatar gitter-badger avatar javascript-journal avatar johnthad avatar joseherminiocollas avatar josephclay avatar koresar avatar nkbt avatar sethlivingston avatar tcrosen avatar troutowicz avatar unstoppablecarl avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.