Composition vs Inheritance in Games
The Inheritance Instinct
Most developers reach for inheritance first because it is what object-oriented programming teaches. You see that a player and an enemy are both characters, so you create a base Entity class with shared fields like position and health, then a Character subclass for things that move and fight, then Player and Enemy beneath that. As long as the objects fall into a clean tree, this feels natural and reads well. The hierarchy mirrors how we intuitively categorize things, and the first handful of objects slot in perfectly.
The approach holds up for a while. Shared behavior lives in the base classes, specific behavior lives in the leaves, and the tree expresses the relationships clearly. The problems only begin when the game grows beyond the neat categories the tree was designed around, which always happens, because games are built on novel combinations rather than tidy taxonomies.
Where the Tree Breaks
The breaking point arrives with the object that needs traits from two different branches. Imagine the hierarchy has MovingEntity for things that move and DestructibleEntity for things with health that can be destroyed. Now you need a flying turret that has health and can be destroyed but does not move, and a moving platform that travels but cannot be destroyed, and a destructible moving vehicle that needs both. None of these fit cleanly into a single-inheritance tree, because each one needs to pull from branches that the tree keeps separate.
Developers respond to this in predictable, painful ways. They push shared behavior up into the base class, so the base class slowly bloats with movement, health, AI, and rendering that not every object needs, leaving objects carrying dead capabilities. Or they duplicate code across branches that cannot share an ancestor. Or they create increasingly specific combinations like FlyingDestructibleStationaryEntity until the hierarchy is a thicket nobody can navigate. This is the classic problem that the gang-of-four design principle, favor composition over inheritance, was written to address, and it bites games especially hard because games are nothing but unusual combinations of traits.
Inheritance forces every object into one branch of a tree. Games are built from combinations that cross branches, so the tree inevitably either bloats at the top or sprawls into unmanageable special cases.
The Composition Alternative
Composition flips the question. Instead of asking what an object is, you ask what an object has. An object is not a position in a hierarchy. It is a bag of capabilities assembled from independent parts. A player has a transform, a sprite, a velocity, a health pool, and an input controller. An enemy has a transform, a sprite, a velocity, a health pool, and an AI controller. A flying turret has a transform, a sprite, a health pool, and a weapon, but no velocity. A moving platform has a transform, a sprite, and a velocity, but no health.
Each capability is a small, focused piece that does one thing and knows nothing about the others. The same velocity part is reused by everything that moves. The same health part is reused by everything destructible. Creating a new kind of object is no longer a matter of finding its place in a rigid tree, it is a matter of choosing which parts to give it. The flying destructible vehicle that was impossible to express with single inheritance is trivial with composition: it simply has all the relevant parts. Nothing needs to be restructured, because the parts were independent to begin with.
Composition in Practice
You can adopt composition at several levels of formality. The lightest version is to give each game object an array or map of component instances, where each component holds some data and optionally an update method, and the object's update simply calls each component in turn. The player object holds a movement component and an input component, the enemy holds a movement component and an AI component, and they literally share the same movement component class. This is straightforward to implement in plain JavaScript and captures most of the benefit with very little machinery.
A more structured version separates the data from the logic entirely, which is exactly what an entity component system does. There, components become pure data with no methods, and the logic moves into systems that operate on every entity holding a given set of components. This is composition taken to its conclusion, and it brings additional benefits in performance and clarity at the cost of more abstraction. The important point is that ECS is not a separate idea from composition, it is the most rigorous expression of it.
Communication between composed parts is worth thinking about. When components are small and independent, they sometimes need to coordinate, and you do not want them reaching directly into each other and rebuilding the coupling you escaped. An event system is the usual answer: a component announces that something happened, and any other component or system that cares can respond, without the announcing component knowing who is listening. Composition and events work together to keep the pieces both modular and able to cooperate.
When Inheritance Still Makes Sense
Composition being the better default does not make inheritance useless. Shallow inheritance, one or two levels deep, is perfectly reasonable for genuine is-a relationships that will not need to cross with other traits. A base class that provides a small amount of truly universal shared behavior, with a handful of subclasses that specialize it, can be cleaner than composition for simple cases. The advice is to favor composition, not to ban inheritance entirely.
The failure to avoid is the deep, wide hierarchy that tries to express every kind of game object through its position in a tree. That structure does not survive contact with a real game's appetite for novel combinations. Reach for composition as the default way to build game objects, keep any inheritance shallow and limited to relationships that are genuinely fixed, and you will avoid the slow calcification that deep hierarchies inflict on a growing codebase.
Mixins and Other Middle Grounds
Between deep inheritance and full component composition lies a range of middle-ground techniques that JavaScript supports well. Mixins are the most common: instead of a class inheriting from a single parent, you copy a set of methods and properties from one or more mixin objects onto a class or instance, so an object can gain movement behavior from one mixin and health behavior from another without either being its parent. This gives some of the flexibility of composition while keeping a familiar object-with-methods feel, and it sidesteps the single-branch limitation of a class tree.
Mixins are not a complete escape from the problems of inheritance, though. Because they copy behavior directly onto objects, name collisions between mixins must be managed, and the source of any given method can become unclear when several mixins contribute to one object. They blur the line between data and behavior rather than separating it the way a strict entity component system does. For small and medium games, mixins are a pragmatic tool that delivers most of the composition benefit with minimal ceremony, and many shipped JavaScript games use them rather than a formal ECS.
The broader lesson is that composition is a spectrum, not a single technique. At the light end is an object holding a few component instances, in the middle are mixins and plain component arrays, and at the rigorous end is a full entity component system with pure-data components and logic in systems. The right point on that spectrum depends on the game's scale and the team's comfort. What matters is the underlying shift in thinking, away from defining objects by their place in a hierarchy and toward defining them by the parts they are built from. Once that shift happens, the specific mechanism is a matter of how much structure the project warrants.