You can add initializers (aka constructors) to your stamps.

const Logger = stampit({
init({level = 50}) {
this.level = level
}
})
const logger = Logger({ level: 42 })
logger.level === 42

Each initializer will be executed on object creation. (But the list of initializers is always deduplicated.)

const Server = stampit(Logger, {
init({ port = process.env.PORT }) {
this.port = port
}
})
const server = Server({ port: 6666 })
server.level === 50
server.port === 6666

If you return anything from an initializer then it becomes the object instance.

const NullServer = Server.init(function () {
return null
})
const server = NullServer()
server === null

Descriptor merging algorithm

The initializers are concatenated into a deduplicated array. As the result, the order of composition becomes the order of initializer execution.

const {init} = stampit
const Log1 = init(() => console.log(1))
const Log2 = init(() => console.log(2))
const Log3 = init(() => console.log(3))
const MultiLog = stampit(Log1, Log2, Log3)
MultiLog() // Will print three times:
// 1
// 2
// 3
// because there are 3 initializers
MultiLog.compose.initializers.length === 3

Stamps remove duplicate initializers.

const {init} = stampit
const func = () => console.log(1)
const Log1 = init(func)
const Log2 = init(func)
const Log3 = init(func)
const MultiLog = stampit(Log1, Log2, Log3)
MultiLog() // Will print only once:
// 1
// because there is only one initializer
MultiLog.compose.initializers.length === 1

Initializer arguments

NOTE

Parameter - a variable being passed to a function.

Argument - a variable received by a function.

You can pass multiple parameters to your stamp while creating an object. First parameter passed as is to all initializers. But the rest of the parameters are available inside the {args} property of the second initializer argument.

const MultiArg = stampit({
init(arg1, { args }) {
arg1 === 'foo'
args[0] === arg1 // first argument of the initializer is passed from factory first parameter
args[0] === 'foo'
args[1] === 'BAR'
args[2] === 'thing'
}
})
MultiArg('foo', 'BAR', 'thing')

If there is no first parameter then an empty object is passed as the first argument.

const NoException = stampit({
init({ iAmUndefined }) { // won't throw exception in this line
iAmUndefined === undefined
console.log(arguments[0]) // will print empty object: {}
}
})
NoException(/* nothing here! */)

Every initializer second argument is always this object: { stamp, args, instance }. Where:

  • stamp is the stamp which was used to create this object. Useful to retrieve stamp's metadata (aka descriptor).

  • args the parameters passed to the stamp while creating the object.

  • instance the object instance itself. Always equals this context of the initializer.

const PrintMyArgs = stampit({
init(_, { stamp, args, instance }) {
console.log('Creating object from this stamp:', stamp)
console.log('List of arguments:', args)
console.log('Object instance:', instance)
this === instance
}
})

Other ways to add initializers

Exactly the same stamp can be created in few ways. Here they all are.

function myInitializer ({ level = 50 }) {
this.level = level
}
const Logger = stampit({
init: myInitializer
})
const Logger = stampit({
init: [myInitializer]
})
const Logger = stampit({
initializers: myInitializer
})
const Logger = stampit({
initializers: [myInitializer]
})
const Logger = stampit.init(myInitializer)
const Logger = stampit.init([myInitializer])
const Logger = stampit.initializers(myInitializer)
const Logger = stampit.initializers([myInitializer])
const Logger = stampit().init(myInitializer)
const Logger = stampit().init([myInitializer])
const Logger = stampit().initializers(myInitializer)
const Logger = stampit().initializers([myInitializer])