Extend object behavior dynamically without modifying its source
When to Use
You need to add responsibilities to objects at runtime without subclassing
You want to compose behaviors (logging, caching, auth checks) around existing functions
Building higher-order functions that wrap existing logic with cross-cutting concerns
Instructions
Write a decorator function that accepts a target function or object and returns an enhanced version.
For class decorators (TC39 Stage 3): prefix the class or method declaration with @decorator.
For functional decorators: wrap the original function — const enhanced = decorate(original).
The decorator should not modify the original — it returns a new function/object.
// Functional decorator — adds logging
function withLogging(fn) {
return function (...args) {
console.log(`Calling ${fn.name} with`, args);
const result = fn.apply(this, args);
console.log(`${fn.name} returned`, result);
return result;
};
}
function add(a, b) {
return a + b;
}
const loggedAdd = withLogging(add);
loggedAdd(2, 3); // logs call and return
Stack decorators by composing them: const fn = withAuth(withLogging(handler)).
Preserve the original function's name and length with Object.defineProperty if needed.
Details
The Decorator pattern adds behavior to individual objects without affecting other objects of the same class. In JavaScript, this is most naturally expressed as higher-order functions — functions that take a function and return a new function with added behavior.
Trade-offs:
Stacking many decorators makes stack traces deeper and harder to debug
Decorated functions lose the original's .name and .length unless explicitly preserved
Order of decoration matters — withAuth(withLogging(fn)) logs before auth checks
When NOT to use:
When the added behavior is always needed — just include it in the function directly
When a simple wrapper function is sufficient — do not over-engineer with a formal decorator abstraction
For complex object augmentation — consider mixins or composition instead
Read the instructions and examples in this document.
Apply the patterns to your implementation, adapting to your specific context.
Verify your implementation against the details and edge cases listed above.
Harness Integration
Type: knowledge — this skill is a reference document, not a procedural workflow.
No tools or state — consumed as context by other skills and agents.
Success Criteria
The patterns described in this document are applied correctly in the implementation.
Edge cases and anti-patterns listed in this document are avoided.
1---2name: js-decorator-pattern3description: JS Decorator Pattern4---5# JS Decorator Pattern67> Extend object behavior dynamically without modifying its source89## When to Use1011- You need to add responsibilities to objects at runtime without subclassing12- You want to compose behaviors (logging, caching, auth checks) around existing functions13- Building higher-order functions that wrap existing logic with cross-cutting concerns1415## Instructions16171. Write a decorator function that accepts a target function or object and returns an enhanced version.182. For class decorators (TC39 Stage 3): prefix the class or method declaration with `@decorator`.193. For functional decorators: wrap the original function — `const enhanced = decorate(original)`.204. The decorator should not modify the original — it returns a new function/object.2122```javascript23// Functional decorator — adds logging24function withLogging(fn) {25 return function (...args) {26 console.log(`Calling ${fn.name} with`, args);27 const result = fn.apply(this, args);28 console.log(`${fn.name} returned`, result);29 return result;30 };31}3233function add(a, b) {34 return a + b;35}36const loggedAdd = withLogging(add);37loggedAdd(2, 3); // logs call and return38```39405. Stack decorators by composing them: `const fn = withAuth(withLogging(handler))`.416. Preserve the original function's `name` and `length` with `Object.defineProperty` if needed.4243## Details4445The Decorator pattern adds behavior to individual objects without affecting other objects of the same class. In JavaScript, this is most naturally expressed as higher-order functions — functions that take a function and return a new function with added behavior.4647**Trade-offs:**4849- Stacking many decorators makes stack traces deeper and harder to debug50- Decorated functions lose the original's `.name` and `.length` unless explicitly preserved51- Order of decoration matters — `withAuth(withLogging(fn))` logs before auth checks5253**When NOT to use:**5455- When the added behavior is always needed — just include it in the function directly56- When a simple wrapper function is sufficient — do not over-engineer with a formal decorator abstraction57- For complex object augmentation — consider mixins or composition instead5859## Source6061https://patterns.dev/javascript/decorator-pattern6263## Process64651. Read the instructions and examples in this document.662. Apply the patterns to your implementation, adapting to your specific context.673. Verify your implementation against the details and edge cases listed above.6869## Harness Integration7071- **Type:** knowledge — this skill is a reference document, not a procedural workflow.72- **No tools or state** — consumed as context by other skills and agents.7374## Success Criteria7576- The patterns described in this document are applied correctly in the implementation.77- Edge cases and anti-patterns listed in this document are avoided.
Run npx skillmds@latest add intense-visions/js-decorator-pattern in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
JS Decorator Pattern It is listed under Coding & Dev Tools on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
Intense-Visions (@intense-visions) published this skill. Their other Agent Skills are listed on their SkillMD profile.