@bblocks/compose

0.1.2 • Public • Published

Discover super powers of composition and inheritance in javascript with compose library

This library is a handy helper if you work with objects, inheritance and composition, like to code efficiently and need to support all modern browser and IE11 without transpiling.

Quick start

Solving problem #1: Composition of objects keeping property descriptors

Solving problem #2: IE11 doesn't support Object.assign, Object.getOwnPropertyDescriptors

Solving problem #3: Bulky code to define properties, inherit and compose object using native javascript methods

Have some fun

Quick start

install

npm install @bblocks/compose --save-dev

include

<!-- include the library -->
<script src="https://cdn.jsdelivr.net/npm/@bblocks/compose@0.1.1/compose.umd.js"></script>
// Optionally create shortcuts in lodash style 
var _ = Object.assign(_ || compose); // Now you can use helpers from the library_.mix  _.clone _.Block _.block

enjoy

// Composition
_.mix({prop1: 1}, {prop2: 2});

// Inheritance
_.clone({prop1: 1}, {prop2: 2}, {foo: function() {}});

// Handy object with built-in features to compose, clone and define properties
var myObj = new _.Block({prop1:1}); // Our building block
var myClone = myObj
	.mix({prop2:2}) 
	.define({
		prop3: {
			get: function() {return 3},
		}
	})
	.clone({prop4: 4});

// Check results
console.log(myClone.__proto__, myClone.prop1, myClone.prop2, myClone.prop3, myClone.prop4); // {...} 1 2 3 4

Problem: Composition of objects keeping property descriptors

Objects became more powerful in javascript since ES5. Now we can create super powerful objects thanks to property descriptors.

Let me show you. In the first example we create and object that can display numbers with suffixes like 1M, 1k, 1b etc...

// Display big numbers with suffixes
var bigNumber = {
	suffixes: ["", "k", "m", "b","t"],
	toString: function (value) {
		var newValue = value;
		if (value >= 1000) {
			var suffixes = this.suffixes;
			var suffixNum = Math.floor( (""+value).length/3 );
			var shortValue = '';
			for (var precision = 2; precision >= 1; precision--) {
				shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
				var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
				if (dotLessShortValue.length <= 2) { break; }
			}
			if (shortValue % 1 != 0)  shortNum = shortValue.toFixed(1);
			newValue = shortValue+suffixes[suffixNum];
		}
		return newValue;
	}
};
console.log('100000 = ' + bigNumber.toString(100000)); // 1000000 = 1m 
// We can automatically generate a short string when value changes thanks to getters and setters 
Object.defineProperty(bigNumber, 'value', {
	get: function() {
		return this._value || 0;
	},
	set: function(newValue) {
		if (newValue != this._value) {
			this.stringValue = this.toString(newValue);
		}
		this._value = newValue;
	}
});
// Create a new instance
var myNumber = Object.create(bigNumber);
myNumber.value = 1000;
console.log(myNumber.value + ' = ' + myNumber.stringValue); // 1000 = 1k

I discovered a problem that we loose all property descriptors when we try to compose two objects.

// Define a new feature to increment a number
var increment = {
	increment: function() {
		this.value = (this.value || 0) + 1;
	}
}

// Compose increment and big number features  
var incNumber = Object.create(increment);
Object.assign(incNumber, bigNumber);

incNumber.increment(); // value = 1;

console.log(incNumber.value); // 1
console.log(incNumber.stringValue); // undefined :(

So we lost all the magic after composition. But you can use mix or clone methods from the library to solve this problem.

// Re-define our mixed object
var myIncNumber = _.clone(increment);
_.mix(myIncNumber, bigNumber);
// or
var myIncNumber2 = _.clone(increment, bigNumber);


myIncNumber.increment();
myIncNumber2.value = 1000;
console.log(myIncNumber.stringValue, myIncNumber2.stringValue); // 1, 1k

IE11 doesn't support Object.assign, Object.getOwnPropertyDescriptors

We can use native javascript function Object.assign for composition.

var sourceObj = {prop1:1};
Object.assign(sourceObj, {prop2: 2}); // Fails in IE11
console.log(sourceObj.prop1 + sourceObj.prop2); // 3

But in order to keep descriptors we need to use something like this.

var sourceObj = {prop1:1};
var extraObj = Object.defineProperty({}, 'prop2', {get: function() {return 2;}});
Object.defineProperties(sourceObj, Object.getOwnPropertyDescriptors(extraObj)); // Fails in IE11. Object doesn't support property or method 'getOwnPropertyDescriptors'
console.log(sourceObj.prop1 + sourceObj.prop2); // 3

Besides helpful mix and clone methods the library goes with two polyfills. Including the library automatically fixes the problem in IE11.

Problem: Bulky code to define properties, inherit and compose object using native javascript methods

The example above looks bulky in native JS code.

var sourceObj = {prop1:1};
var extraObj = Object.defineProperty({}, 'prop2', {get: function() {return 2;}});
Object.defineProperties(sourceObj, Object.getOwnPropertyDescriptors(extraObj));
console.log(sourceObj.prop1 + sourceObj.prop2); // 3

Library has a bonus for you. A handy Block you can start with.

var extraObj = (new _.Block()).define({prop2: {get: function() {return 2;}}});
var sourceObj = (new _.Block({prop1:1})).mix(extraObj);
console.log(sourceObj.prop1 + sourceObj.prop2); // 3

Let me explain step by step.

// create new objects 
var obj = new _.Block({prop1:1}); 

// composing with other objects
obj.mix({prop2: 2}); 

// configuring properties with descriptors
obj.define({prop3: {get: function() {return 3;}}});

// inherit
var myClone = obj.clone({prop4: 4});

// Checking results
console.log(myClone.prop1 + myClone.prop2 + myClone.prop3 + myClone.prop4); // 1 + 2 + 3 + 4 = 10

// You can use multiple arguments and chaining
var myClone = (new _.Block({prop1: 1}))
		.mix({prop2: 2})
		.define({prop3: {get: function() {return 3;}}})
		.clone({prop4: 4});

// Checking results
console.log(myClone.prop1 + myClone.prop2 + myClone.prop3 + myClone.prop4); // 1 + 2 + 3 + 4 = 10

Dependencies (0)

    Dev Dependencies (8)

    Package Sidebar

    Install

    npm i @bblocks/compose

    Weekly Downloads

    127

    Version

    0.1.2

    License

    MIT

    Unpacked Size

    26.7 kB

    Total Files

    8

    Last publish

    Collaborators

    • webrealizer