stampit API
  • Introduction
  • Essentials
    • What is a Stamp
    • Installation
    • Specification
      • Merging algorithm
      • Object creation internals
    • FAQ
  • API
    • Quick start
    • Basics
    • Methods
    • Properties
    • Deep properties
    • Initializers
    • Static properties
    • Static deep properties
    • Configuration
    • Deep configuration
    • Composers
    • Property descriptors
    • Static property descriptors
    • Name
  • Ecosystem
    • Ecosystem Overview
    • @stamp/collision
    • @stamp/required
    • @stamp/privatize
    • @stamp/named (DEPRECATED)
    • @stamp/instanceof
Powered by GitBook
On this page
  1. Essentials
  2. Specification

Object creation internals

PreviousMerging algorithmNextFAQ

Last updated 6 years ago

This is a plain factory function. It creates and returns a plain object.

function myFactory () {
  return { myProperty: 'my value' }
}

But Stamps are a little different. They carry around the metadata about the object they are going to produce. The metadata is attached to the Stamp.compose object:

function Stamp () {
  const metadata = Stamp.compose // retrieving metadata from itself

  ... SNIP ...

  return newObject
}

There are 11 types of metadata, such as properties and deepProperties.

function Stamp () {
  const metadata = Stamp.compose // retrieving metadata from itself

  const properties = metadata.properties // retrieving properties from the metadata
  let deepProperties = metadata.deepProperties // retrieving deepProperties from the metadata
  deepProperties = JSON.parse(JSON.stringify(deepProperties)) // we need to clone deepProperties
  const newObject = Object.assign({}, deepProperties, properties) // creating new object using the properties

  ... SNIP ...

  return newObject
}

There is also methods object which becomes the new object's prototype.

function Stamp () {
  const metadata = Stamp.compose // retrieving metadata from itself

  const properties = metadata.properties // retrieving properties from the metadata
  let deepProperties = metadata.deepProperties // retrieving deepProperties from the metadata
  deepProperties = _.cloneDeep(deepProperties) // we need to clone deepProperties
  const newObject = Object.assign({}, deepProperties, properties) // creating new object using the properties

  const methods = metadata.methods // retrieving methods from the metadata
  if (methods) Object.setPrototypeOf(newObject, methods) // assigning new object's prototype

  ... SNIP ...

  return newObject
}
function Stamp () {
  const metadata = Stamp.compose // retrieving metadata from itself

  const properties = metadata.properties // retrieving properties from the metadata
  let deepProperties = metadata.deepProperties // retrieving deepProperties from the metadata
  deepProperties = JSON.parse(JSON.stringify(deepProperties)) // we need to clone deepProperties
  const newObject = Object.assign({}, deepProperties, properties) // creating new object using the properties

  const methods = metadata.methods // retrieving methods from the metadata
  if (methods) Object.setPrototypeOf(newObject, methods) // assigning new object's prototype

  Object.defineProperties(newObject, metadata.propertyDescriptors)

  ... SNIP ...

  return newObject
}

Last, but not least, the initializers are kind of constructors. With classic classes you would execute only one constructor when creating an object. With stamps you execute all the initializers of a stamp.

function Stamp () {
  const metadata = Stamp.compose // retrieving metadata from itself

  const properties = metadata.properties // retrieving properties from the metadata
  let deepProperties = metadata.deepProperties // retrieving deepProperties from the metadata
  deepProperties = JSON.parse(JSON.stringify(deepProperties)) // we need to clone deepProperties
  const newObject = Object.assign({}, deepProperties, properties) // creating new object using the properties

  const methods = metadata.methods // retrieving methods from the metadata
  if (methods) Object.setPrototypeOf(newObject, methods) // assigning new object's prototype

  Object.defineProperties(newObject, metadata.propertyDescriptors)

  for (const init of metadata.initializers || []) { // run every initializer one by one
    const firstArg = argument[0]
    const secondArg = { args: [...arguments], instance: newObject, stamp: Stamp }
    const returnedValue = init.call(newObject, firstArg, secondArg)
    if (returnedValue !== undefined) {
      newObject = returnedValue
    }
  }

  return newObject
}

If an initializer returns a non-undefined value then it becomes the new object instance.

NOTE

The code above is not the actual stampit code. It was optimized for readability purposes.

The propertyDescriptors metadata is an object applied to the resulting object using JavaScript standard function.

See for more details.

standardized
Object.defineProperties
Stamp Specification