JavaScript and TypeScript make it dangerously easy to treat object references as disposable. You create an object, pass it to a function, store it in a cache, and later replace the variable with a fresh instance. The language does not complain. The old reference still exists somewhere else in your program, pointing to data that is no longer current. This is not a crash. It is something worse: a silent divergence between two parts of your codebase that both think they own the truth.
The discipline that prevents this is called Hard Object References. It is not a library or a compiler feature. It is a contract you enforce across your code.
The Stale Alias Problem
A stale alias happens when one module holds a reference to an object while another module replaces that object with a new one. The first reference is still valid code, but it no longer points to current data.
Picture a user record in a typical web application:
const user = {
name: "Alice",
address: {
city: "Seoul",
country: "KR"
}
};
A shipping component captures the address early:
const shippingAddress = user.address;
Later, a profile update arrives. A reducer or service handler decides to replace the entire object:
user.address = { city: "Tokyo", country: "JP" };
At this point, user.address points to Tokyo. But shippingAddress still points to the old object in Seoul. No exception is thrown. TypeScript is happy because the types still match. The UI might show the updated city on the profile page while the shipping label quietly prints the old one. The bug only surfaces when a user complains that their package went to the wrong country.
This happens because JavaScript separates identity from value. When you replace an object property with a new object literal, you break the chain. The old object is not destroyed; it is merely orphaned. Anyone still holding it is working with a ghost.
What Hard Object References Mean
The rule is simple: replace primitive values, but never replace object or array references. When new data arrives, you copy it into the existing container instead of swapping the container out.
This requires three concrete habits.
First, declare objects and arrays with const. This removes the temptation to rebind the top-level variable to a new instance. The variable should remain fixed for the lifetime of the scope.
Second, never replace a property that holds an object or array with a freshly created one. If you need to update an address, mutate the properties inside it.
Third, if you need to clear or reset state, empty the existing structure rather than discarding it for a new empty object or array.
Revisiting the address example, the correct update looks like this:
user.address.city = "Tokyo";
user.address.country = "JP";
If the incoming data is partial or dynamic, use Object.assign to write into the existing target:
Object.assign(user.address, incomingAddressData);
The shippingAddress variable, which points to the exact same object in memory, now sees the new fields immediately. There is only one canonical object serving as the live source of truth.
Where This Matters Most
The discipline seems like overkill for a flat configuration object. It becomes essential once your state grows into a graph where multiple subsystems hold pointers to overlapping nodes.
Consider a rich text editor. The document model is a tree of nodes. A selection model holds references to the start and end nodes. The history buffer holds references to nodes that changed in the last operation. The rendering layer holds references to nodes it measured for layout. If the state manager replaces a paragraph node with a new object because its text changed, every one of those subsystems is now holding a stale alias. The selection highlights the wrong region. The history system cannot revert correctly. The renderer crashes or, worse, displays phantom cursors.
The same risk appears in user profiles with nested settings and permissions referenced by the UI, the access-control layer, and the autosave routine. It appears in layout engines where parent containers cache measurements of child nodes. It appears in visual editors and canvas tools where a runtime controller tracks active entities by reference. In all of these domains, components grab a handle to an object and expect that handle to remain a live view of the truth.
Hard Object References treat the object as a stable address. The furniture inside can change, but the door stays in the same place. Anyone holding the address can walk in and see the current layout.
Reactivity Instead of Replacement
Als je hebt gewerkt met Redux of vergelijkbare immutable state-libraries, klinkt dit model waarschijnlijk achterstevoren. In die systemen wordt een verandering gesignaleerd door een nieuw object te produceren. De verandering van de referentie is het signaal. Componenten vergelijken prevProps.data === nextProps.data om te weten of ze opnieuw moeten renderen.
Hard Object References vereisen dat je die aanname omdraait. Omdat de referentie constant blijft, zegt referentie-gelijkheid niets over de vraag of de data is veranderd. Je hebt een andere manier nodig om updates te verzenden.
In de praktijk betekent dit dat je moet vertrouwen op reactiviteitssystemen, expliciete observers of dirty flags. Het muteren van user.address.city kan een setter triggeren die subscribers op de hoogte stelt. Een object kan een change event uitzenden via een event bus. Een game loop of canvas-tool kan een globale dirty flag instellen en de grafiek aan het einde van de frame opnieuw scannen. De referentie is stabiel, dus je moet de datastroom zichtbaar maken via andere mechanismen.
Deze architecturale verschuiving is de reden waarom deze aanpak het beste past bij complexe frontend state, grote component-lokale state, visuele editors, canvas-tools en runtime controllers. Deze systemen vertrouwen al op granulaire updates, directe mutaties of imperatieve API's. Het forceren van immutability bovenop deze systemen zorgt vaak voor excessieve allocation pressure en reference churn, zonder dat dit proportioneel meer duidelijkheid oplevert. Wanneer elke frame telt, is het alloceren van een nieuwe objectgrafiek enkel om een slider te bewegen verspilling. De referentie 'hard' houden en de inhoud muteren sluit aan bij de werkelijke mechanica van het probleem.
Het laten beklijven
Een van de over het hoofd geziene voordelen van deze regel is
