Functions, Scope & Object Model

Object Composition

Composition builds behavior by combining smaller capabilities rather than relying on deep inheritance. JavaScript makes composition natural because objects and functions are flexible runtime values.
  • Composition favors small capabilities
  • Decorators wrap behavior without changing the original
  • Dependency injection is composition
  • Mixins are composition with sharp edges
  • Composition is easier to test when boundaries are explicit
Composition over deep inheritance
Each wrapper adds one behavior around a smaller core.
Composed service wrapper
function withRetry(service, retries = 3) {
  return {
    async save(data) {
      let lastError
      for (let attempt = 0; attempt < retries; attempt++) {
        try {
          return await service.save(data)
        } catch (err) {
          lastError = err
        }
      }
      throw lastError
    },
  }
}
The wrapper composes retry behavior without changing the original service.
Reuse strategies
StrategyStrengthWeakness
Class inheritanceShared API and polymorphismCan become rigid/deep
CompositionFlexible behavior assemblyNeeds clear boundaries
DecoratorWrap behavior locallyToo many wrappers can obscure flow
MixinReuse method groupsName collisions and hidden assumptions
Sources
  • The Modern JavaScript TutorialObjects and prototypes
  • You Don’t Know JS YetObjects and Classes
  • MDN JavaScript Guide and ReferenceWorking with objects