Tangram.js
A library for class-free object-oriented programming in JavaScript.
I used to think that the important innovation of JavaScript was prototypal inheritance. I now think it is class-free object-oriented programming. I think that is JavaScript’s gift to humanity. That is the thing that makes it really interesting, special, and an important language. -- Douglas Crockford
Contents
Getting Started
Installation
npm install tangramjs --save
Integration
var createObject = require('tangramjs').createObject;
API
createObject
This is the immutable base factory of Tangram.js. It has no property descriptors, and thus, it can only create new immutable empty objects.
factory([spec])
Creates a new object which has an immutable set of own properties and no prototype.
With the optional argument spec
the default values of specific properties, writable or not, can be overwritten at construction time.
factory.val(name[, defaultValue])
Creates a new immutable factory, copying all existing property descriptors and the new one. The new property descriptor takes precedence over the existing ones and describes an enumerable and non-writable property.
factory.var(name[, defaultValue])
Creates a new immutable factory, copying all existing property descriptors and the new one. The new property descriptor takes precedence over the existing ones and describes an enumerable and writable property.
factory._val(name[, defaultValue])
Creates a new immutable factory, copying all existing property descriptors and the new one. The new property descriptor takes precedence over the existing ones and describes an non-enumerable and non-writable property.
factory._var(name[, defaultValue])
Creates a new immutable factory, copying all existing property descriptors and the new one. The new property descriptor takes precedence over the existing ones and describes an non-enumerable and writable property.
factory.ext(otherFactory)
Creates a new immutable factory, copying all property descriptors of both factories. The property descriptors of the left-hand side factory are taking precedence over the other ones.
References
- Douglas Crockford: The Better Parts - JSConfUY 2014
- Douglas Crockford: Nordic.js 2014 - The Better Parts
- Danny Fritz: Class-Free Object-Oriented Programming
- Eric Elliott: JavaScript Constructor Functions Vs Factory Functions
- Eric Elliott: Stop Using Constructor Functions In JavaScript
- Wikipedia: Composition over inheritance
Examples
An Alligator, a Duck, and a Goat
Creating a new factory called createAnimal
:
var createAnimal = createObject
.val('name', 'animal');
Creating a new factory called createFlyingAnimal
:
var createFlyingAnimal = createAnimal
._val('fly', function () {
console.log(this.name + ' makes flap flap');
});
Creating a new factory called createSwimmingAnimal
:
var createSwimmingAnimal = createAnimal
._val('swim', function () {
console.log(this.name + ' makes splish splash');
});
Creating a new factory called createTalkingAnimal
:
var createTalkingAnimal = createAnimal
.val('word', '...')
._val('talk', function () {
console.log(this.name + ' says ' + this.word);
});
Creating a new factory called createWalkingAnimal
:
var createWalkingAnimal = createAnimal
._val('walk', function () {
console.log(this.name + ' makes stomp stomp');
});
Creating a new factory called createAlligator
:
var createAlligator = createSwimmingAnimal
.ext(createTalkingAnimal)
.ext(createWalkingAnimal)
.val('name', 'alligator')
.val('word', 'grrr');
Creating a new factory called createDuck
:
var createDuck = createFlyingAnimal
.ext(createSwimmingAnimal)
.ext(createTalkingAnimal)
.ext(createWalkingAnimal)
.val('name', 'duck')
.val('word', 'quack');
Creating a new factory called createGoat
:
var createGoat = createTalkingAnimal
.ext(createWalkingAnimal)
.val('name', 'goat')
.val('word', 'baa');
Creating and using a new immutable object called alligator
:
var alligator = createAlligator();
alligator.swim(); // alligator makes splish splash
alligator.talk(); // alligator says grrr
alligator.walk(); // alligator makes stomp stomp
Creating and using a new immutable object called duck
:
var duck = createDuck();
duck.fly(); // duck makes flap flap
duck.swim(); // duck makes splish splash
duck.talk(); // duck says quack
duck.walk(); // duck makes stomp stomp
Creating and using a new immutable object called goat
:
var goat = createGoat();
goat.talk(); // goat says baa
goat.walk(); // goat makes stomp stomp
Object.prototype
Creating an object that behaves like it inherits from Creating a new factory called createStandardObject
:
var createStandardObject = createObject
._val('hasOwnProperty', Object.prototype.hasOwnProperty)
._val('propertyIsEnumerable', Object.prototype.propertyIsEnumerable)
._val('toLocaleString', Object.prototype.toLocaleString)
._val('toString', Object.prototype.toString)
._val('valueOf', Object.prototype.valueOf);
Creating a new factory called createPerson
:
var createPerson = createStandardObject
.val('name', 'John Doe')
.val('age', 0);
Creating and using a new immutable object called person
:
var person = createPerson({
name: 'Jane Doe',
age: 99
});
console.log(person.hasOwnProperty('name')); // true
console.log(person.propertyIsEnumerable('name')); // true
console.log(person.toLocaleString()); // [object Object]
console.log(person.toString()); // [object Object]
console.log(person.valueOf()); // { name: 'Jane Doe', age: 99 }