const chain = require('chainchainchain')
Let's consider the following being, human, robot, cop and doc objects.
let being = { is: 'being' }
let human = { is: 'human' }
let robot = { is: 'robot' }
let cop = { is: 'cop' }
let doc = { is: 'doc' }
We create a chain object alex with cop and robot as the chained objects.
let alex = chain(cop, robot)
We can give the chain object alex its own properties.
alex.name = 'alex'
Let's use our evaluation methods on this new chain object.
chain.is(alex) true
chain.origin(alex) { name: 'alex' }
chain.arr(alex) [ { name: 'alex' }, { is: 'cop' }, { is: 'robot' } ]
As expected we confirm that we have a chain alex, that its origin has a property name and that the whole chain is composed by alex's origin, cop and robot.
If we add being to the chain we get:
chain.add(alex, being) [ { name: 'alex' },
{ is: 'cop' },
{ is: 'robot' },
{ is: 'being' } ]
The chain object returns inherited properties like you would expect of an inheritance chain:
alex.name 'alex'
alex.is 'cop'
We got the name property from alex's origin and the is property from cop as it's the youngest object in the chain with that property. We can get all the is properties of this chain in one method call:
chain.raw(alex, 'is') [ undefined, 'cop', 'robot', 'being' ]
Methods work as expected:
being.hi = function () {
return 'Hi, my name is ' + this.name + ' and I am a ' + this.is
}
alex.hi() 'Hi, my name is alex and I am a cop'
The chain inherits the method hi from being and apllies it to itself by default while chain.set.owncontext === false. The function is removed from its own context and binds to the chain instead, returning this.name from alex's origin and this.is from cop.
Chains are independent from each other:
let joe = chain(cop, human, being) Ch { … }
joe.name = 'joe'
joe.hi() 'Hi, my name is joe and I am a cop'
alex.hi() 'Hi, my name is alex and I am a cop'
delete cop.is true
joe.hi() 'Hi, my name is joe and I am a human'
alex.hi() 'Hi, my name is alex and I am a robot'
You can chain chain objects creating complex inheritance trees. Let's replace cop by a new chain containing cop and a new skilled object.
let skilled = {
is: 'skilled',
skill: 'shooting'
}
cop.is = 'cop' 'cop'
let branch = chain(cop, skilled)
chain.rep(alex, cop, branch) [ { name: 'alex' },
Ch { … },
{ is: 'robot' },
{ is: 'being', hi: [Function] } ]
chain.rep(joe, cop, branch) [ { name: 'joe' },
Ch { … },
{ is: 'human' },
{ is: 'being', hi: [Function] } ]
alex keeps it's length of 4 objects:
chain.arr(alex).length 4
But we now have access to the skilled object's properties.
alex.skill 'shooting'
alex.is 'cop'
chain.raw(alex, 'is') [ undefined, 'cop', 'robot', 'being' ]
delete cop.is true
chain.raw(alex, 'is') [ undefined, 'skilled', 'robot', 'being' ]
alex.is 'skilled'
The same for joe:
chain.raw(joe, 'is') [ undefined, 'skilled', 'human', 'being' ]
cop.is = 'cop' 'cop'
chain.raw(joe, 'is') [ undefined, 'cop', 'human', 'being' ]
chain.raw(joe, 'is', (props => console.log(props))) [ undefined, 'cop', 'human', 'being' ]
We can change the way the chain behaves through the chain.set object:
chain.set.owncontext = true true
Bind methods to their corresponding object's context instead of the origin object.
chain.set.uniqueness = true
Deprecated.
chain.set.allowloops = true true
Allow for inheritance loops when chaining chain objects.
chain.set.setchained = true true
Allow values to be manipulated on all objects in chain owning the property key.
All values of the set object default to false and are converted to a boolean on attribution.
All of this is independent from the prototypical inheritance scheme, so you can use both tools at the same time to create truly intricate functionalities in your programs with low overhead.
I am a Portuguese web developer, designer and drummer from the city of Porto. If you have any doubts, suggestions or a will to buy me a beer get in touch. Also check out my portfolio.