# Object creation internals

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

```javascript
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:

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

  ... SNIP ...

  return newObject
}
```

There are 11 [standardized](/essentials/specification.md) types of metadata, such as **properties** and **deepProperties**.

```javascript
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.

```javascript
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
}
```

The **propertyDescriptors** metadata is an object applied to the resulting object using [`Object.defineProperties`](https://mdn.io/defineProperties) JavaScript standard function.

```javascript
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&#x20;*****all*****&#x20;the initializers** of a stamp.

```javascript
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.

See [Stamp Specification](/essentials/specification.md) for more details.

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://stampit.js.org/essentials/specification/object-creation-internals.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
