Advanced Composition and Metadata
Introduction: Beyond Traditional Inheritance
In our previous lessons, we explored how to build robust classes and how to share logic through inheritance. We saw how a SavingsAccount could inherit from a base Account to gain its features. While inheritance is powerful, it is also very rigid. It creates a strict parent-child relationship that can sometimes make your code difficult to change. If you have many different behaviors — like logging, auditing, or tagging — trying to fit them all into a single inheritance tree often leads to "messy" code where classes do too much.
In this lesson, we will look at two modern patterns that help us move beyond simple inheritance. First, we will learn how to use a WeakMap to store data about an object without actually modifying the object itself. This is perfect for tasks like creating an audit log that stays separate from the object's public properties. Second, we will learn about mixins. Mixins allow us to "plug in" specific behaviors to any class we want, giving us the flexibility to combine multiple features horizontally rather than vertically.
Understanding WeakMap
JavaScript provides a special kind of collection called a WeakMap. At first glance, it looks like a regular Map, but it has two very important differences. The first difference is that the keys in a WeakMap must be objects. You cannot use a string or a number as a key. The second, and most important, difference involves garbage collection. In a standard Map, if you use an object as a key, that object will stay in the computer's memory as long as the Map exists. This can sometimes lead to memory leaks, where your program uses more and more RAM over time.
A WeakMap solves this by holding "weak" references to its keys. When no strong references to the key object remain, the WeakMap entry can be garbage-collected automatically. This makes it an ideal tool for storing extra information about an object without worrying about cleaning up the memory later.
However, WeakMap has specific limitations. Unlike a standard Map, it cannot be iterated and does not expose a size property; you must already have the key object to retrieve its metadata. Generally, you should use a Map when enumeration is required, and a WeakMap when object-keyed metadata and garbage-collection friendliness matter. Note that any "privacy" provided by a WeakMap is scope-based: metadata is hidden from the object instance, but remains accessible to any code that has a reference to the WeakMap variable itself.
