object
Pattern: Foundation of Doh InstancesThe object
pattern is the base pattern or root pattern that all other Doh Patterns implicitly inherit from. It provides the essential functionality required for object instance creation (New()
) and management, including inheritance resolution, lifecycle phase management, and the automatic building of child objects (sub-object-building).
This guide covers:
object
pattern as a base.object
base pattern.object
pattern.object
Pattern in ContextThe object
pattern sits at the intersection of several key Doh systems:
object
is the root pattern that all other patterns ultimately extendobject
provides the basic inheritance mechanismsobject
establishes the phase execution systemobject
implements the auto-building functionalityThis integration creates a cohesive foundation for Doh's component architecture.
In Doh, objects are created from "ideas," which are plain JavaScript object literals. This transformation occurs through the New()
function for synchronous patterns or AsyncNew()
for patterns with asynchronous phase handlers:
// Define an idea
let buttonIdea = {
text: 'Click Me',
onClick: function() {
console.log('Button clicked!');
}
};
// Create a Doh object using the 'object' pattern (synchronous)
let buttonObject = New('object', buttonIdea);
// Create a Doh object with async phases (asynchronous)
let asyncButtonObject = await AsyncNew('object', buttonIdea);
This process involves:
object_phase
and builder_phase
)After construction, a Doh object has several key internal properties:
// Internal structure (simplified)
buttonObject = {
// User-defined properties from the idea
text: 'Click Me',
onClick: function() { console.log('Button clicked!'); },
// Internal properties (normally not enumerable)
inherits: ['object'],
inherited: {
object: { /* reference to object pattern */ },
idea: { /* reference to original idea */ }
},
moc: { /* melded MOC definitions */ },
machine: function(phase) { /* phase control function */ }
object_phase: function() { /* melded method executor */ }
builder_phase: function() { /* melded method executor */ }
}
The object
pattern establishes the basic Melded Object Composition (MOC) structure that governs how properties are composed:
moc: {
object_phase: 'phase',
builder_phase: 'phase'
}
This definition specifies that object_phase
and builder_phase
should use the 'phase' melding type—a special method melding behavior for lifecycle phases.
The object
pattern implements the core object lifecycle phase execution engine through its machine
function, which:
// Advancing an object to a specific phase
myObject.machine('html_phase');
The object_phase
is the initial setup phase for all Doh objects:
object_phase: function() {
// Handle static properties
for (let prop_name in this.moc) {
if (this.moc[prop_name] === 'STATIC') {
// Connect to pattern statics
for (pattern in this.inherited) {
if (NotUndefined(this.inherited[pattern][prop_name])) {
Doh.mimic(this, prop_name, this.inherited[pattern], prop_name);
break;
}
}
}
}
}
Asynchronous Object Phase:
When using AsyncNew()
, the object_phase
can be asynchronous for patterns that need to perform async initialization:
// Pattern for a database-connected component
Pattern('DatabaseComponent', {
async object_phase() {
// Initialize database connection asynchronously
this.connection = await this.connectToDatabase();
// Load initial data
this.userData = await this.connection.query('SELECT * FROM users WHERE active = 1');
// Set up caching
this.cache = new Map();
this.userData.forEach(user => this.cache.set(user.id, user));
console.log(`DatabaseComponent initialized with ${this.userData.length} active users`);
// Return values get merged onto this object
return {
ready: true,
userCount: this.userData.length,
lastInit: new Date()
};
},
async connectToDatabase() {
// Simulate async database connection
await new Promise(resolve => setTimeout(resolve, 100));
return { query: async (sql) => [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }] };
}
});
// Must use AsyncNew for patterns with async phases
const dbComponent = await AsyncNew('DatabaseComponent');
console.log(dbComponent.ready); // true
console.log(dbComponent.userCount); // 2
This phase handles essential object setup, including:
Because of how phases work, patterns can all have their own 'object_phase' and all the different methods will be stitched together, making it a proper behavioral init path.
The builder_phase
is responsible for automated child object construction, integrating tightly with the Sub-Object-Builder system:
builder_phase: function() {
// Collect all sub-object-buildable properties into this.built
Doh.collect_buildable_ideas(this, this.moc, this, '');
// Build all child objects
if (this.built) {
this.machine_built = function(phase) {
// Implementation that builds child objects
};
this.machine_built(this.machine_built_to);
}
}
This phase is crucial for:
One of the most powerful features enabled by the object
pattern is its integrated sub-object-building system, which automatically constructs child objects from property definitions.
builder_phase
, Doh scans the object for properties with a pattern
attributebuilt
objectNew()
// Before builder_phase
myComponent = {
header: { pattern: 'html', tag: 'header' }
};
// After builder_phase
myComponent = {
header: /* Fully built Doh object */
};
Properties should be defined in the idea object or pattern definition (before the builder_phase
runs):
// Best practice: Define sub-object-buildable properties in the idea
let pageObject = New('object', {
header: {
pattern: 'html',
tag: 'header',
html: 'Page Title'
},
content: {
pattern: 'html',
tag: 'main',
html: 'Page content goes here'
}
});
The object
pattern establishes a robust parent-child relationship system:
Builder Reference: Each auto-built object gets a builder
property pointing to its parent
// Parent object with child objects
let form = New('object', {
submitButton: {
pattern: 'Button',
text: 'Submit',
// Child object can access parent methods
onClick: function() {
this.builder.submitForm();
}
},
// Parent method
submitForm: function() {
console.log('Form submitted!');
}
});
The inheritance system in Doh is remarkably flexible, allowing for multiple convenient ways to specify inheritance relationships.
Doh's inheritance system accepts the inherits
property in multiple formats:
This flexibility appears throughout the system:
// PATTERN DEFINITION: Multiple ways to specify inheritance
// 1. Single inheritance as second argument
Pattern('ButtonPattern', 'UIComponent', {
// Button-specific properties
});
// 2. Multiple inheritance as array in second argument
Pattern('DropdownButton', ['Button', 'Dropdown'], {
// Combined functionality
});
// 3. Complex inheritance through inherits property
Pattern('AdvancedComponent', {
inherits: {
BaseComponent: true, // Hard inheritance
OptionalComponent: false, // Soft inheritance
ConditionalComponent: { // Conditional inheritance
DependencyComponent: true
}
},
// Component properties
});
// OBJECT CREATION: Similarly flexible inheritance
// 1. Direct inheritance through pattern name
let button = New('ButtonPattern', {
label: 'Click Me'
});
// 2. Multiple inheritance as first argument
let specialButton = New(['Button', 'Draggable'], {
label: 'Drag Me'
});
// 3. Inheritance through inherits property in idea
let customObject = New('object', {
inherits: ['BasePattern', 'MixinPattern'],
// Custom properties
});
// 4. Combining approaches
let complexComponent = New(['BaseComponent', 'UIComponent'], {
inherits: {
'SpecialFeature': true,
'OptionalFeature': false
},
// Additional properties
});
The inheritance system is designed to be both powerful and convenient, allowing you to easily:
// Ad-hoc composition example
let specialButton = New(['Draggable', 'Resizable', 'Button'], {
label: 'Special Button',
});
When multiple patterns are inherited, Doh resolves effective order by first expanding all branches of the inheritance tree, then flattening to a list that respects prerequisites and explicit ordering. Keep in mind:
moc
definition combine according to their melder type (e.g., Method
, Array
, Object
). If a property's moc
type is set to 'Override'
, or if it has no melder defined, it is replaced by the most specific later application (often the idea). This makes 'Override'
the explicit way to enforce replacement behavior and prevent meldingThis powerful inheritance system is central to Doh's pattern-based composition, enabling clean, reusable, and flexible code structures.
Explicit Inheritance: When creating patterns, explicitly inherit from 'object' or another pattern.
MOC Definitions: Always define MOC types for properties that need special handling.
Phase Methods: Place initialization code in the appropriate phase methods.
Sub-Object-Building: Define child objects in the idea or pattern definition, not in phase methods.
Parent-Child Relationships: Use the builder chain navigation methods to maintain loose coupling.
For more detailed information on related topics, see: