Suggest an editImprove this articleRefine the answer for “What WeakRef does”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`WeakRef` is an object holding a weak reference to another object, that is, a reference that does not stop the garbage collector (GC) from removing that object once nothing else refers to it strongly.** You create one with `new WeakRef(obj)` and read the value with `.deref()`, which returns either the original object or `undefined` if the GC has already collected it. The moment of collection is unpredictable, so you cannot rely on the object's lifetime. The practical scenarios are narrow: caching and memoisation without memory leaks, observers that must not keep an object alive, caching heavy resources. Together with `FinalizationRegistry` you can learn that an object has been collected, although that callback is not guaranteed in time either. `WeakRef` landed in ES2021. ```javascript let user = { name: 'Tim' }; const weakRef = new WeakRef(user); user = null; // no strong references left console.log(weakRef.deref()?.name); // 'Tim' or undefined, depending on the GC ``` **Key point:** `WeakRef` lets you remember an object while it is alive without artificially keeping it in memory.Shown above the full answer for quick recall.Answer (EN)Image**`WeakRef` (weak reference) is an object that holds a weak reference to another object, that is, a reference which does not stop the garbage collector from removing that object.** Put simply, `WeakRef` lets you remember an object while it is alive without artificially keeping it in memory. ## Theory ### TL;DR - `new WeakRef(obj)` creates a weak reference to `obj`. - `weakRef.deref()` returns the object, or `undefined` if the GC has already collected it. - Unlike a normal reference, a weak one **does not prevent** garbage collection. - The moment the GC runs is unpredictable, so the object's lifetime cannot be guaranteed. - Useful in narrow scenarios: leak-free caches, memoisation, observers, heavy resources. - `FinalizationRegistry` gives you a callback when an object is collected, with no timing guarantees. - Added in ES2021; ordinary code usually has no need for it. ### Quick example ```javascript let user = { name: 'Tim' }; const weakRef = new WeakRef(user); user = null; // there are no strong references any more // ...later, maybe... console.log(weakRef.deref()?.name); // 'Tim' or undefined ``` The object can now be removed by the GC at any moment, and then `weakRef.deref()` returns `undefined`. ### Strong and weak references An ordinary (strong) reference keeps the object in memory: ```javascript let user = { name: 'Tim' }; let ref = user; // an ordinary, strong reference user = null; // but ref still holds the object console.log(ref.name); // 'Tim' ``` The object **will not be removed** by the garbage collector as long as at least one strong reference (`ref`) exists. A weak reference behaves differently: it is not counted when deciding whether the object is still needed. ### How `WeakRef` works 1. `new WeakRef(obj)` creates a weak reference. 2. `weakRef.deref()` tries to return the original object, if it is still alive. 3. If the object has already been collected by the GC, `deref()` returns `undefined`. The real behaviour looks like this: ```javascript let ref; (() => { let bigObject = { data: 'Some heavy data...' }; ref = new WeakRef(bigObject); })(); // bigObject is no longer reachable directly setTimeout(() => { console.log(ref.deref()); // either the object or undefined, up to the GC }, 1000); ``` The garbage collector runs at an unspecified moment. There is no way to predict when exactly `deref()` will start returning `undefined`. ### Why `WeakRef` exists Normally JavaScript does not ask you to manage memory by hand, but there are narrow cases where `WeakRef` helps: | Scenario | Example | | --- | --- | | **Leak-free caching** | You want to cache objects without holding them in memory forever | | **Memoisation** | Keep a computed result for an object while that object is alive | | **Reactive systems and observers** | Watch an object without preventing its collection | | **Game engines and graphics** | Cache heavy resources (textures, data) but let the GC clear them | | **Integration with FinalizationRegistry** | React when an object has been collected | A plain `Map` holds its keys strongly: ```javascript const cache = new Map(); function getUserData(user) { if (!cache.has(user)) { cache.set(user, heavyCompute(user)); } return cache.get(user); } ``` The problem is that even when `user` is no longer needed, the `Map` will not let the GC remove it until the cache is cleared by hand. The fix is to store a weak reference in the cache: ```javascript const cache = new Map(); function getUserData(user) { const ref = cache.get(user); let data = ref?.deref(); if (!data) { data = heavyCompute(user); cache.set(user, new WeakRef(data)); } return data; } ``` Now, if `data` is not used anywhere else, the GC frees it and `ref.deref()` simply returns `undefined`. ### Pairing with `FinalizationRegistry` To find out **when an object was collected by the GC**, use `FinalizationRegistry`: ```javascript const registry = new FinalizationRegistry(id => { console.log(`Object ${id} was removed from memory`); }); let user = { name: 'Tim' }; registry.register(user, 'user#1'); let ref = new WeakRef(user); user = null; ``` When the GC collects `user`, the callback fires: ```text Object user#1 was removed from memory ``` Important: the call is not guaranteed in time and may not happen at all before the process ends. ### When not to use `WeakRef` Do not use it: - to manage ordinary data; - to "speed up" the GC, which is pointless; - to store state in React, Vue or Next.js; - in critical logic chains where the result cannot suddenly disappear. What to keep in mind: | Property | Description | | --- | --- | | `WeakRef` does not prevent collection | The object may vanish at any moment | | `deref()` may return `undefined` | If the GC has already removed the object | | You cannot rely on lifetime | The GC is unpredictable | | Do not use it without a reason | It can lead to "zombie" bugs where an object disappears suddenly | | Useful only in special scenarios | Caches, memoisation, integration with the GC | Summary: | Question | Answer | | --- | --- | | What it does | Creates a weak reference to an object | | How it works | Does not stop the GC from removing the object | | Method | `.deref()` returns the object or `undefined` | | Useful for | Caches, memoisation, memory tracking | | Risks | The object may disappear at any moment | | Introduced in | ES2021 | ### Common mistakes - **Expecting `deref()` to always return the object.** It can return `undefined`; always check the result. - **Caching the result of `deref()` in a long-lived variable.** That creates a strong reference and defeats the point of `WeakRef`. - **Confusing `WeakRef` with `WeakMap`.** `WeakMap` makes its keys weak and cannot be iterated, while `WeakRef` is a single reference to a single value. - **Treating `FinalizationRegistry` as a destructor.** The callback may never fire, so you cannot release files or sockets through it. - **Using `WeakRef` to "help" the garbage collector.** The GC runs on its own schedule; a weak reference does not speed it up. - **Writing tests that ignore how unpredictable the GC is.** A test expecting `undefined` after a `setTimeout` will be flaky.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.