# Series: The JavaScript You Don't Know (8 Parts) — Luca Del Puppo > Complete 8-part technical series "The JavaScript You Don't Know" by Luca Del Puppo (https://delpuppo.net/blog/series/javascript-you-dont-know/). Ordered chronologically from Part 1 to Part 8. - **Canonical Series URL**: https://delpuppo.net/blog/series/javascript-you-dont-know/ - **Hashnode Series Mirror**: https://blog.delpuppo.net/series/javascript-you-dont-know - **Blog Index LLMs.txt**: https://delpuppo.net/blog/llms.txt ## Series Curriculum 1. [Part 1: Unveiling the Magic: Exploring JavaScript Symbols](https://delpuppo.net/blog/javascript-you-dont-know/unveiling-the-magic-exploring-javascript-symbols/) (Sep 20, 2023) — Introduction to JavaScript Symbols JavaScript Symbols are a new primitive data type... ([Article LLMs.txt](https://delpuppo.net/blog/javascript-you-dont-know/unveiling-the-magic-exploring-javascript-symbols/llms.txt)) 2. [Part 2: Unlocking JavaScript's Secret Weapon: The Power of WeakMaps](https://delpuppo.net/blog/javascript-you-dont-know/unlocking-javascripts-secret-weapon-the-power-of-weakmaps/) (Sep 27, 2023) — Introduction JavaScript is a powerful and versatile programming language that has evolved... ([Article LLMs.txt](https://delpuppo.net/blog/javascript-you-dont-know/unlocking-javascripts-secret-weapon-the-power-of-weakmaps/llms.txt)) 3. [Part 3: Unlock the Power of JavaScript WeakSet: Mastering a Hidden Gem!](https://delpuppo.net/blog/javascript-you-dont-know/unlock-the-power-of-javascript-weakset-mastering-a-hidden-gem/) (Oct 4, 2023) — In the vast landscape of JavaScript, many powerful features often go unnoticed. One such hidden gem... ([Article LLMs.txt](https://delpuppo.net/blog/javascript-you-dont-know/unlock-the-power-of-javascript-weakset-mastering-a-hidden-gem/llms.txt)) 4. [Part 4: JavaScript WeakRef Explained: Harnessing Memory Management Magic](https://delpuppo.net/blog/javascript-you-dont-know/javascript-weakref-explained-harnessing-memory-management-magic/) (Oct 11, 2023) — Introduction to WeakRef WeakRef is a powerful feature in JavaScript that allows developers... ([Article LLMs.txt](https://delpuppo.net/blog/javascript-you-dont-know/javascript-weakref-explained-harnessing-memory-management-magic/llms.txt)) 5. [Part 5: Unlocking the Power of Proxies: JavaScript's Secret Superheroes](https://delpuppo.net/blog/javascript-you-dont-know/unlocking-the-power-of-proxies-javascripts-secret-superheroes/) (Oct 18, 2023) — JavaScript's Proxy object is a powerful feature that enables you to intercept and customize... ([Article LLMs.txt](https://delpuppo.net/blog/javascript-you-dont-know/unlocking-the-power-of-proxies-javascripts-secret-superheroes/llms.txt)) 6. [Part 6: JavaScript FinalizationRegistry Unraveled: Memory Management Magic Explained!](https://delpuppo.net/blog/javascript-you-dont-know/javascript-finalizationregistry-unraveled-memory-management-magic-explained/) (Oct 25, 2023) — Introduction JavaScript's memory management can be tricky, especially when it comes to... ([Article LLMs.txt](https://delpuppo.net/blog/javascript-you-dont-know/javascript-finalizationregistry-unraveled-memory-management-magic-explained/llms.txt)) 7. [Part 7: Cracking the JavaScript Code: Unveil the Magic of Object Property Descriptors](https://delpuppo.net/blog/javascript-you-dont-know/cracking-the-javascript-code-unveil-the-magic-of-object-property-descriptors/) (Nov 2, 2023) — 👋 Hey, JavaScript developers! Ever wondered what makes your objects tick? Or how to go all... ([Article LLMs.txt](https://delpuppo.net/blog/javascript-you-dont-know/cracking-the-javascript-code-unveil-the-magic-of-object-property-descriptors/llms.txt)) 8. [Part 8: The Reflect API: The Swiss Army Knife Every JavaScript Developer Needs](https://delpuppo.net/blog/javascript-you-dont-know/the-reflect-api-the-swiss-army-knife-every-javascript-developer-needs/) (Nov 9, 2023) — Ever wished for a magical toolkit that gives you superhero-like control over JavaScript objects? Say... ([Article LLMs.txt](https://delpuppo.net/blog/javascript-you-dont-know/the-reflect-api-the-swiss-army-knife-every-javascript-developer-needs/llms.txt)) --- ## Full Series Content ### Part 1 of 8: Unveiling the Magic: Exploring JavaScript Symbols - **URL**: https://delpuppo.net/blog/javascript-you-dont-know/unveiling-the-magic-exploring-javascript-symbols/ - **Published**: Sep 20, 2023 - **Tags**: javascript, es6, symbols, js ## Introduction to JavaScript Symbols JavaScript Symbols are a new primitive data type introduced in ECMAScript 6 (ES6). They are used as unique, non-string identifiers for object properties, useful in avoiding naming collisions and enabling more advanced programming techniques. > 🎬 **Watch / View Embedded Resource:** [https://youtu.be/o8YDHAS-fo0](https://youtu.be/o8YDHAS-fo0) ## Creating and Understanding Symbols Symbols are created using the `Symbol()` function, which can take an optional description as an argument. Each symbol is unique; even if two symbols have the same description, they are considered distinct. ```js const propSymbol = Symbol("propName"); const propSymbol2 = Symbol("propName"); propSymbol === propSymbol2 // false ``` ## Unique Identifiers and Property Keys Symbols are often used as property keys in objects to ensure uniqueness and prevent naming collisions. They can be used alongside string keys without conflict, and their uniqueness makes them ideal for use as metadata or private properties in objects. ```js const propSymbol = Symbol("propName"); const propSymbol2 = Symbol("propName"); const obj = { [propSymbol]: "propSymbol", [propSymbol2]: "propSymbol2" } ``` ## The Global Symbol Registry The global Symbol registry allows you to create and share symbols across different scopes and realms. To create a global symbol, use `Symbol.for(key)`, which takes a string as its argument. This method checks if a symbol with the same key exists in the registry; if not, it creates a new one. ```js // my-module-1.js export const propSymbol = Symbol("propName"); export const propSymbolShare = Symbol.for("propName"); // my-module-2.js export const propSymbol = Symbol("propName"); export const propSymbolShare = Symbol.for("propName"); // index.js import { propSymbol as propSymbolM1, propSymbolShare as propSymbolShareM1 } from './my-module.js' import { propSymbol as propSymbolM2, propSymbolShare as propSymbolShareM2 } from './my-module-2.js' console.log(propSymbolM1 === propSymbolM2); // false console.log(propSymbolM1 === propSymbolShareM1); // false console.log(propSymbolM2 === propSymbolShareM2); // false console.log(propSymbolShareM1 === propSymbolShareM2); // true ``` It's also possible to retrieve the key of a Symbol using `Symbol.keyFor(key)` but only for shared keys. ```js export const propSymbol = Symbol("propName"); export const propSymbolShare = Symbol.for("propName"); console.log(Symbol.keyFor(propSymbol)); // undefined console.log(Symbol.keyFor(propSymbolShare)); // propName ``` ## Symbols and Iteration Symbols are not enumerable, which means they are not included in standard iteration methods like `for...in` loops or `Object.keys()`. To access an object's symbol properties, use `Object.getOwnPropertySymbols()`. ```js const propSymbol = Symbol("propName"); const propSymbol2 = Symbol("propName"); const obj = { [propSymbol]: "propSymbol", [propSymbol2]: "propSymbol2" } console.log(JSON.stringify(obj)); // {} console.log(Object.keys(obj)); // [] console.log(Object.getOwnPropertyNames(obj)); // [] for (const key in obj) { console.log(key); // nothing } console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(propName), Symbol(propName)] ``` ## Well-Known Symbols in JavaScript Well-known symbols are predefined global symbols that represent common behaviours in JavaScript, such as `Symbol.iterator`, `Symbol.asyncIterator`, `Symbol.toStringTag`, and `Symbol.species`. These symbols can be used to customize the behaviour of built-in JavaScript objects and classes. ## Use Cases and Practical Applications Symbols can be used to implement private properties, metadata, or methods, avoiding naming collisions in libraries and frameworks. They are also used to customize the behaviour of well-known JavaScript objects and classes, such as iterators and string conversion. ## Limitations and Considerations Symbols are not supported in older JavaScript environments, and their unique nature may require additional care when working with serialization or proxy objects. Additionally, they are not directly accessible during iteration, which may require extra steps to access their properties. ## Conclusion JavaScript Symbols provide a powerful, unique identifier for object properties, helping to avoid naming collisions and enabling advanced programming techniques. Understanding their use cases and limitations is essential for modern JavaScript developers. _You can find the source code_ [in the GitHub repository](https://github.com/Puppo/javascript-you-dont-know/tree/01-symbols) > 🎬 **Watch / View Embedded Resource:** [https://dev.to/puppo](https://dev.to/puppo) --- ### Part 2 of 8: Unlocking JavaScript's Secret Weapon: The Power of WeakMaps - **URL**: https://delpuppo.net/blog/javascript-you-dont-know/unlocking-javascripts-secret-weapon-the-power-of-weakmaps/ - **Published**: Sep 27, 2023 - **Tags**: javascript, es6, weakmap ## Introduction JavaScript is a powerful and versatile programming language that has evolved over the years, introducing new features and improvements to enhance its performance and capabilities. One such feature is the WeakMap, a collection of key-value pairs that offers unique benefits regarding memory management and data privacy. This article will delve into the world of WeakMap in JavaScript, exploring their creation, usage, limitations, and real-world applications. ## Understanding WeakMap In JavaScript, a WeakMap is a type of Map that holds key-value pairs where the keys are objects, and the values can be any arbitrary data. The primary difference between a Map and a WeakMap is how they manage memory management. In a WeakMap, when a key object becomes inaccessible, the entry is automatically removed, allowing the garbage collector to reclaim memory efficiently. ## Creating and Using WeakMap To create a new WeakMap, use the `new WeakMap()` constructor. Once created, you can set values for the keys using the `set` method, as shown below: ```js const weakmap = new WeakMap(); const key = { name: "John Doe" }; weakmap.set(key, "Some value"); ``` To retrieve values associated with keys, use the `get` method: ```js const value = weakmap.get(key); // "Some value" ``` You can remove entries from the WeakMap using the `delete` method and check for the existence of a key using the `has` method: ```js weakmap.delete(key); // true weakmap.has(key); // false ``` ## Practical Applications of WeakMap WeakMap offers several practical applications in JavaScript: 1. Privacy and Encapsulation: By storing private data separately from the object, WeakMap can enhance privacy and encapsulation. This is particularly useful for classes and objects where internal data should not be exposed to the outside world. 2. Memory Management: WeakMap automatically releases unreferenced keys and associated values, allowing for efficient memory management in large applications. 3. Caching: WeakMap can implement caching mechanisms without causing memory leaks, as they automatically remove entries when keys are no longer accessible. ## Limitations of WeakMap Despite their benefits, WeakMap has some limitations: 1. Keys must be objects: Unlike Maps, WeakMap requires keys to be objects, not primitive values. 2. No built-in iteration methods: WeakMap does not have built-in methods for iterating over their entries, such as `forEach` or `entries`. 3. No `clear` method: There is no built-in method to clear the entire WeakMap. 4. Limited compatibility: WeakMap is not supported in some older browsers, limiting their compatibility. ## Real-world Examples and Use Cases WeakMap can be utilized in various real-world scenarios: 1. Event Listeners: When managing event listeners in DOM elements, WeakMap can help prevent memory leaks by automatically removing entries when elements are no longer accessible. 2. Private Data Storage: WeakMap can store private data in classes and objects, ensuring that internal data is not exposed to the outside world. 3. Large Applications: WeakMap can optimize memory usage in large applications by automatically releasing unreferenced data, improving performance and reducing memory leaks. _To find out more about WeakMap don't miss out on my Youtube video on my_ [_Youtube channel_](https://www.youtube.com/@puppo_92)_._ > 🎬 **Watch / View Embedded Resource:** [https://youtu.be/8Z4ZYDSxN3A](https://youtu.be/8Z4ZYDSxN3A) ## Conclusion In conclusion, WeakMap offers powerful features and applications for efficient memory management and data privacy in JavaScript. While they have some limitations, their benefits often outweigh these drawbacks, making them a valuable addition to a JavaScript developer's toolkit. As the language continues to evolve, future developments will likely address these limitations and further improve the usefulness of WeakMap in JavaScript applications. _The code of this article is available_ [in the GitHub repository](https://github.com/Puppo/javascript-you-dont-know/tree/02-weakmaps) > 🎬 **Watch / View Embedded Resource:** [https://dev.to/puppo](https://dev.to/puppo) --- ### Part 3 of 8: Unlock the Power of JavaScript WeakSet: Mastering a Hidden Gem! - **URL**: https://delpuppo.net/blog/javascript-you-dont-know/unlock-the-power-of-javascript-weakset-mastering-a-hidden-gem/ - **Published**: Oct 4, 2023 - **Tags**: javascript, es6, weakset, weaksets, es2015, js In the vast landscape of JavaScript, many powerful features often go unnoticed. One such hidden gem is the WeakSet, an unsung hero of the language that can help you optimize your code and manage memory more effectively. In this article, we'll dive deep into WeakSet, uncovering their potential and learning how to use them effectively in our JavaScript projects. ## A Brief Introduction to WeakSet WeakSet is a collection of objects similar to the more commonly used Set. However, there's a significant difference between the two: WeakSet holds only weak references to the objects stored within them. This means that if an object is only referenced by a WeakSet, it can still be garbage collected, freeing up valuable memory resources. This unique feature of WeakSet makes it an excellent choice for managing certain types of data relationships, mainly when memory management is a priority. ## Creating and Using WeakSet To create a WeakSet, instantiate a new instance of the WeakSet class: ```js const weakSet = new WeakSet(); ``` Adding objects to a WeakSet is easy. Just use the `add` method: ```js const obj1 = {}; const obj2 = {}; weakSet.add(obj1); weakSet.add(obj2); ``` WeakSets also provide methods for checking if an object is present (`has`) and removing objects (`delete`): ```js console.log(weakSet.has(obj1)); // true weakSet.delete(obj1); console.log(weakSet.has(obj1)); // false ``` However, unlike Sets, WeakSets do not have methods for iterating over their contents or determining their size. This is because of their weakly-referenced nature, which makes it impossible to know how many objects are still being held in memory. ## Use Cases for WeakSets ### 1. Managing DOM Elements `WeakSet` can be incredibly useful when working with the DOM. You can store references to DOM elements without worrying about memory leaks. When an element is removed from the DOM, the reference in the `WeakSet` will be automatically garbage collected. ```js const domElements = new WeakSet(); const element = document.querySelector('.my-element'); domElements.add(element); // Later, when the element is removed from the DOM domElements.has(element); // false (garbage collected) ``` ### 2. Private Data Storage `WeakSet` can be used to store private data associated with an object without exposing it. Since the references are weak, the data will be automatically removed when the object is no longer reachable. ```js const privateData = new WeakSet(); class MyClass { constructor() { privateData.add(this); } #data = 'I am private data'; getData() { if (privateData.has(this)) { return this.#data; } return undefined; } } ``` To see WeakSets in action, don't waste the opportunity to look at my YouTube video about them. > 🎬 **Watch / View Embedded Resource:** [https://youtu.be/m3BKqgeVAa4](https://youtu.be/m3BKqgeVAa4) ## In Conclusion WeakSet may not be the most well-known feature of JavaScript, but it offers unique capabilities that can be invaluable in certain situations. By understanding and embracing WeakSet, you can optimize your code, enhance memory management, and unlock the full potential of this hidden gem in the JavaScript universe. You can find the source code [in the GitHub repository](https://github.com/Puppo/javascript-you-dont-know/tree/03-weaksets) > 🎬 **Watch / View Embedded Resource:** [https://dev.to/puppo](https://dev.to/puppo) --- ### Part 4 of 8: JavaScript WeakRef Explained: Harnessing Memory Management Magic - **URL**: https://delpuppo.net/blog/javascript-you-dont-know/javascript-weakref-explained-harnessing-memory-management-magic/ - **Published**: Oct 11, 2023 - **Tags**: javascript, es6, weakref, weakrefs, js ## Introduction to WeakRef WeakRef is a powerful feature in JavaScript that allows developers to create weak object references. A weak reference is a reference that does not prevent the object it refers to from being garbage collected. This can be useful when you want to maintain a reference to an object without preventing it from being cleaned up by the garbage collector. ## How WeakRef Works WeakRef works by creating a weak reference to an object. This reference does not count towards the object's reference count and does not prevent it from being garbage collected. To access the object, you can call the `deref()` method on the WeakRef instance. If the object is still alive, the method will return the object; otherwise, it will return undefined. ## Implementing WeakRef in Your Code To use WeakRef in your code, follow these steps: 1. Create a new WeakRef instance by passing the object you want to reference as an argument: `const weakRef = new WeakRef(targetObject);` 2. To access the object, call the `deref()` method on the WeakRef instance: `const object = weakRef.deref();` 3. Check if the object is still alive by testing if it is not undefined: `if (object !== undefined) { /* object is still alive */ }` ## Use Cases for WeakRef WeakRef can be helpful in several scenarios, such as: 1. **Caching**: Use WeakRef to create a cache for expensive-to-create objects. When an object is no longer needed, it can be garbage collected automatically, freeing up memory. 2. **DOM Element References**: In web applications, you can use WeakRef to hold references to DOM elements. This can help prevent memory leaks when you need to keep track of elements for event handling or manipulation. 3. **Resource Cleanup**: When working with external resources like files or network connections, you can use WeakRef to keep track of those resources. If the resource becomes unused (e.g., a file is closed or a network connection is no longer needed), it can be automatically released. 4. **Memoization**: Implement memoization using WeakRef to store the results of function calls. This allows you to cache function results without preventing the input arguments from being garbage-collected when they're no longer needed. 5. **Managing Timers**: When using timers (e.g., setTimeout or setInterval), you can use WeakRef to hold references to objects associated with the timer. This can help ensure that the timer doesn't keep objects alive longer than necessary. 6. **Event Handling**: In event-driven applications, you can use WeakRef to manage event listeners. When an object with event listeners is no longer in use, the associated event listeners can be automatically removed. 7. **Reacting to DOM Node Removal**: In cases where you want to perform actions when DOM nodes are removed, you can use WeakRef to track DOM nodes. When a node is removed from the DOM, you can receive a notification and perform cleanup tasks. 8. **Custom Data Structures**: Create custom data structures that use WeakRef to hold references to elements. This can be particularly useful in scenarios like implementing caches or data structures with automatic cleanup. 9. **Managing Web Workers**: When working with Web Workers, you can use WeakRef to manage references to worker instances. When a worker is no longer needed, its reference can be automatically released. 10. **Optimizing Memory-Intensive Applications**: In memory-intensive applications, you can use WeakRef to ensure that large data structures or objects are only kept in memory as long as they're actively used. ## Best Practices and Limitations When using WeakRef, keep in mind the following best practices and limitations: 1. Use WeakRef only when necessary, as it can introduce complexity and potential performance issues. 2. Do not rely on the timing of garbage collection, as it may vary across JavaScript engines and environments. 3. Be aware that WeakRef is not supported in all environments, so you may need to provide a fallback implementation or polyfill. If you want to learn more about WeakRef, don't miss out on my YouTube video on [my YouTube channel](https://www.youtube.com/@Puppo_92) 🚀 > 🎬 **Watch / View Embedded Resource:** [https://youtu.be/-rN03KAHGC4](https://youtu.be/-rN03KAHGC4) ## Conclusion WeakRef is a powerful feature in JavaScript that allows you to create weak references to objects, enabling you to maintain references without preventing garbage collection. By understanding how WeakRef works and its use cases, you can use memory more efficiently in your applications and avoid memory leaks. [_Here is_](https://github.com/Puppo/javascript-you-dont-know/tree/04-weakrefs) _the source code of this post._ > 🎬 **Watch / View Embedded Resource:** [https://dev.to/puppo](https://dev.to/puppo) --- ### Part 5 of 8: Unlocking the Power of Proxies: JavaScript's Secret Superheroes - **URL**: https://delpuppo.net/blog/javascript-you-dont-know/unlocking-the-power-of-proxies-javascripts-secret-superheroes/ - **Published**: Oct 18, 2023 - **Tags**: javascript, es6, proxy, proxies, js JavaScript's Proxy object is a powerful feature that enables you to intercept and customize operations performed on objects. This versatile tool allows developers to create more efficient and flexible code while also improving code maintainability. In this article, we will dive into the world of JavaScript proxies, explore their use cases, and provide examples for expert developers. ## A Brief Introduction to Proxies in JavaScript A Proxy object in JavaScript is used to define custom behaviour for fundamental operations such as property lookup, assignment, enumeration, and function invocation. It acts as a wrapper around another object, called the target, and allows you to intercept and manipulate operations performed on the target object. ### Creating a JavaScript Proxy To create a JavaScript Proxy, you need two things: a target object and a handler object. The target object is the object you want to wrap with the Proxy, while the handler object defines the custom behaviour for the proxy. Here's a simple example of creating a Proxy: ```js const target = { name: "John", surname: "Doe", fullName: "John Doe" }; const handler = { get(_target, prop) { return _target[prop] ? _target[prop].toUpperCase() : "Property not found"; }, set(_target, prop, value) { if (prop === 'name') { _target.fullName = value + ' ' + _target.surname; } if (prop === 'surname') { _target.fullName = _target.name + ' ' + value; } if (prop === 'fullName') { throw new Error('fullName is not writable') } _target[prop] = value; return true; } }; const proxy = new Proxy(target, handler); console.log(proxy.fullName); // Output: "JOHN DOE" console.log(proxy.nonexistent); // Output: "Property not found" proxy.name = 'Jane'; console.log(proxy.fullName); // Output: "Jane Doe" proxy.surname = 'Smith'; console.log(proxy.fullName); // Output: "Jane Smith" proxy.fullName = 'Tom Smith'; // Error: fullName is not writable ``` In this example, we defined a `get` trap in the handler object, which intercepts the property lookup operation on the target object. When a property is accessed on the proxy object, the `get` trap is invoked, and it returns the property value in uppercase if the property exists or a custom message if it doesn't. Then, we defined a `set` trap, which intercepts a property's set. If the property name is `name` or `surname` calculates the `fullName` and sets the target object with the right value, but if you try to set the `fullName` property the code raises an error. ### Use Cases for Proxies in JavaScript #### Validation and Constraints Proxies can be used to enforce data validation and constraints when setting properties on an object. For example, you can ensure that a property value is a certain type or within a specific range. ```js const target = { age: 25 }; const handler = { set(_target, prop, value) { if (prop === "age" && (typeof value !== "number" || value < 0 || value > 150)) { throw new TypeError("Invalid age value"); } _target[prop] = value; return true; }, }; const proxy = new Proxy(target, handler); proxy.age = 30; // Works fine proxy.age = "thirty"; // Throws TypeError: "Invalid age value" ``` #### Logging and Profiling Proxies can be used to log and profile operations performed on an object, which can be helpful during debugging and performance analysis. ```js const target = { message: "Hello, World!" }; const handler = { get(_target, prop) { console.log(`Accessing property "${prop}"`); return _target[prop]; }, set(_target, prop, value) { console.log(`Setting property "${prop}" to "${value}"`); _target[prop] = value; return true; }, }; const proxy = new Proxy(target, handler); console.log(proxy.message); // Logs: "Accessing property "message"" and outputs: "Hello, World!" proxy.message = "Goodbye, World!"; // Logs: "Setting property "message" to "Goodbye, World!"" ``` To learn more don't miss my YouTube video about JavaScript Proxy on my [YouTube channel](https://www.youtube.com/@Puppo_92) > 🎬 **Watch / View Embedded Resource:** [https://www.youtube.com/watch?v=e7_lxSrP_Ok](https://www.youtube.com/watch?v=e7_lxSrP_Ok) ## Conclusion JavaScript's Proxy object is a powerful and versatile feature that allows developers to create more efficient and flexible code. By understanding and utilizing proxies, you can unlock their full potential and become a true JavaScript superhero. _You can find the code of this article_ [in the GitHub repository](https://github.com/Puppo/javascript-you-dont-know/tree/05-proxies)_._ > 🎬 **Watch / View Embedded Resource:** [https://dev.to/puppo](https://dev.to/puppo) --- ### Part 6 of 8: JavaScript FinalizationRegistry Unraveled: Memory Management Magic Explained! - **URL**: https://delpuppo.net/blog/javascript-you-dont-know/javascript-finalizationregistry-unraveled-memory-management-magic-explained/ - **Published**: Oct 25, 2023 - **Tags**: javascript, memory, leak, js, FinalizationRegistry ## Introduction JavaScript's memory management can be tricky, especially when it comes to handling objects that are no longer needed. As developers, we often need to deal with memory leaks and other issues that arise from improper garbage collection. Fortunately, JavaScript has introduced a new feature called the FinalizationRegistry to help us manage memory more efficiently. In this blog post, we'll dive deep into the world of FinalizationRegistry, exploring its purpose, how to use it, and real-world scenarios where it can come in handy. ## A Simple Example To begin, let's take a look at a simple example to understand how FinalizationRegistry works. The FinalizationRegistry is an object that enables you to register a callback function that will be invoked when an object is garbage collected. Here's a basic example: ```js const registry = new FinalizationRegistry((heldValue) => { console.log(`Clean up: ${heldValue}`); }); function createObject() { const obj = {id: 1}; registry.register(obj, "Object 1"); } createObject(); // After some time, when the object is garbage collected, the console will log: "Clean up: Object 1" ``` In this example, we create a new FinalizationRegistry and provide a callback function that logs a message when the registered object is garbage collected. We then create an object and register it with the registry. ## Real-World Scenario Now, let's explore a more realistic scenario where FinalizationRegistry can be beneficial. Imagine we have a web application that allows users to upload and manipulate images. We use a third-party library to handle the image manipulation, and this library creates large objects that consume a significant amount of memory. To prevent memory leaks, we can use FinalizationRegistry to ensure that these objects are properly cleaned up when they are no longer needed. ```js const imageRegistry = new FinalizationRegistry((imageData) => { console.log(`Cleaning up image data: ${imageData}`); // Perform additional cleanup tasks, such as releasing resources associated with imageData }); function loadImage(imageUrl) { return fetch(imageUrl) .then((response) => response.blob()) .then((imageBlob) => { const imageData = new ImageData(imageBlob); imageRegistry.register(imageData, `Image: ${imageUrl}`); return imageData; }); } function manipulateImage(imageData) { // Use the third-party library to manipulate the image } loadImage('https://example.com/image.jpg') .then((imageData) => { manipulateImage(imageData); // After manipulation, the imageData object will eventually be garbage collected }); ``` In this example, we create an imageRegistry using FinalizationRegistry and register the ImageData objects when they are loaded. When an ImageData object is garbage collected, the provided callback function will log a message and perform any additional cleanup tasks required. ## Considerations While the FinalizationRegistry is a powerful tool for managing memory, there are some important considerations to keep in mind: 1. The timing of garbage collection is not guaranteed, and the callback function may not be invoked immediately after an object becomes unreachable. 2. FinalizationRegistry should not be used to manage critical resources, as it only provides a best-effort cleanup mechanism. 3. The held values in the registry should not be used to access the registered objects, as it may prevent them from being garbage collected. To find out more don't waste my YouTube video on my [YouTube channel](https://www.youtube.com/@Puppo_92) > 🎬 **Watch / View Embedded Resource:** [https://www.youtube.com/watch?v=3sgIFrjA61U](https://www.youtube.com/watch?v=3sgIFrjA61U) ## Conclusion The JavaScript FinalizationRegistry is a valuable addition to the language that can help developers manage memory more efficiently and prevent memory leaks. By understanding how it works and knowing when to use it, you can create more performant and memory-efficient applications. Keep in mind the considerations mentioned above, and happy coding! _You can find the code of this article_ [in the GitHub repository](https://github.com/Puppo/javascript-you-dont-know/tree/06-finalizationregistry)_._ > 🎬 **Watch / View Embedded Resource:** [https://dev.to/puppo](https://dev.to/puppo) --- ### Part 7 of 8: Cracking the JavaScript Code: Unveil the Magic of Object Property Descriptors - **URL**: https://delpuppo.net/blog/javascript-you-dont-know/cracking-the-javascript-code-unveil-the-magic-of-object-property-descriptors/ - **Published**: Nov 2, 2023 - **Tags**: javascript, object, descriptor, js, Objects 👋 Hey, JavaScript developers! Ever wondered what makes your objects tick? Or how to go all "Inception" on your JavaScript code by manipulating object properties at a deeper, more granular level? Well, you're in luck! Today, we're diving into the magical world of Object Property Descriptors in JavaScript—a realm where you become the puppet master of your objects. 🎭 Get ready for a roller coaster ride that takes you through the hidden alleys of JavaScript's objects. By the end of this post, you'll be wielding Object Property Descriptors like a wizard casting spells, giving you full control over properties, and even the behaviour of your objects. 🧙 ## What is a JavaScript Object Property Descriptor? In JavaScript, objects are more than just key-value pairs. They're intricate entities with characteristics that often go unnoticed, hidden beneath the surface like an iceberg in an ocean of code. Welcome to the fascinating realm of Object Property Descriptors, a tool that lets you truly tap into the full potential of JavaScript objects. An Object Property Descriptor is essentially a metadata object that details how a property on an object behaves. It's like the DNA of the property, encoding its attributes and defining its characteristics. You can think of an Object Property Descriptor as a control panel, giving you knobs and levers to fine-tune how a property can be accessed, modified, enumerated, or deleted. Here are the attributes you can configure with an Object Property Descriptor: - `value`: The actual value of the property. Simple enough, right? 📦 - `writable`: Determines if the property value can be changed. It's like a lock that you can engage or disengage at will. 🔒 - `enumerable`: Controls whether the property shows up during enumeration, like when you use a `for...in` loop or `Object.keys()`. It's like a spotlight—or lack thereof—on your property. 🔦 - `configurable`: Decides if the property can be deleted or has its attributes changed. Think of it as the ultimate veto power. 🛑 You can access and modify these attributes using built-in JavaScript methods like `Object.getOwnPropertyDescriptor()`, `Object.defineProperty()`, and `Object.defineProperties()`. These are your magic wands to perform spellbinding feats of object manipulation! For example, to make a property read-only, you can set its `writable` attribute to `false`. Or if you want to hide a property from enumeration, just set the `enumerable` attribute to `false`. It's like tailoring your object properties to fit your exact needs, almost as if you're crafting a bespoke suit! ## **Object Property Descriptors in Practice** It's time to get our hands dirty and jump into the practical aspects of using Object Property Descriptors in JavaScript. ### 1. Accessing Descriptors with `Object.getOwnPropertyDescriptor()` Let's start with the basics. Ever wondered what the descriptor of an existing object property looks like? `Object.getOwnPropertyDescriptor()` is your answer. It takes two arguments: the object itself and the property name as a string. ```js const myObj = { age: 30 }; const descriptor = Object.getOwnPropertyDescriptor(myObj, 'age'); console.log(descriptor); // Output: { value: 30, writable: true, enumerable: true, configurable: true } ``` Here, the `descriptor` object shows the default attributes: `value`, `writable`, `enumerable`, and `configurable`. No surprises, everything is set to `true` by default! 🎉 ### 2. Defining Descriptors with `Object.defineProperty()` Okay, ready to step it up? What if you want to create a property with custom attributes? Say hello to `Object.defineProperty()`. It takes three arguments: the object, the property name, and the descriptor object. ```js const person = {}; Object.defineProperty( person, 'name', { value: 'Alice', writable: false, enumerable: true, configurable: false } ); console.log(person.name); // Output: Alice ``` Now, [`person.name`](http://person.name) is read-only and not configurable but still enumerable. Try changing its value, and JavaScript will be like, "Nice try, buddy!" 🤨 ### 3. Batch Operation with `Object.defineProperties()` But wait, there's more! What if you want to define multiple properties at once? `Object.defineProperties()` has got your back. ```js const animal = {}; Object.defineProperties(animal, { name: { value: 'Dog', writable: true }, sound: { value: 'Woof', enumerable: false } }); ``` Here, `animal` gets two properties, each with its own set of descriptors. Efficient, isn't it? 🤓 ### 4. Computed property with `Object.defineProperty()` But wait, there's more again. What if you want to define a property that depends on other ones? `Object.defineProperty()` has got your back again. ```js const person = { firstName: 'John', lastName: 'Doe', }; // Define a read-only property Object.defineProperty(person, 'fullName', { get() { return `${this.firstName} ${this.lastName}`; }, enumerable: true, }); console.log(person.fullName); // John Doe ``` Here `person` has three properties, `firstName`, `lastName` and `fullName`. `fullName` depends on the others and it's enumerable so that it's included in the `for...in` loop and `Object.keys()` method. Ok, I think the idea now it's clear and you can use your imagination to combine these configurations to provide the best descriptors for your objects. To find out more don't waste my YouTube video on my [YouTube Channel](https://www.youtube.com/@Puppo_92) > 🎬 **Watch / View Embedded Resource:** [https://www.youtube.com/watch?v=AHLdUs8LtIA](https://www.youtube.com/watch?v=AHLdUs8LtIA) ## Conclusion In conclusion, Object Property Descriptors are a powerful feature of JavaScript that allows you to manipulate and define object properties with fine-grained control. This advanced feature offers developers the ability to create more dynamic and flexible code. Whether you're a junior developer or an expert, understanding Object Property Descriptors can help you level up your JavaScript skills. So go ahead, tinker with your code, challenge the norms, and keep pushing the boundaries. The JavaScript universe is your playground! 🚀 You can find the code of this article [in the GitHub repository](https://github.com/Puppo/javascript-you-dont-know/tree/07-object-descriptor). > 🎬 **Watch / View Embedded Resource:** [https://dev.to/puppo](https://dev.to/puppo) --- ### Part 8 of 8: The Reflect API: The Swiss Army Knife Every JavaScript Developer Needs - **URL**: https://delpuppo.net/blog/javascript-you-dont-know/the-reflect-api-the-swiss-army-knife-every-javascript-developer-needs/ - **Published**: Nov 9, 2023 - **Tags**: javascript, reflect, js Ever wished for a magical toolkit that gives you superhero-like control over JavaScript objects? Say hello to the `Reflect` API, the Swiss Army knife every modern JavaScript developer needs! From peeping into objects to conjuring custom behaviors `Reflect`is your one-stop spellbook! 📜 Strap in as we teleport through this arcane realm of JavaScript, where we'll not only decode `Reflect`, but also empower you with hands-on examples and practical tips! 🚀 ## **🎯 Core Objectives of Reflect** 1. **Introspection** : Much like looking into a magic mirror, `Reflect` allows you to delve into an object's properties and characteristics, enabling you to perform introspective tasks like checking property existence or retrieving property descriptors. 2. **Manipulation** : Think of `Reflect` as your Swiss Army knife for object operations. You can easily add, delete, or modify object properties and even trap or monitor these operations. 3. **Extensibility** : The `Reflect` API can be seen as a foundational layer that sets the stage for creating Proxy objects, empowering you to build custom behaviors for basic operations (like property lookup, assignment, enumeration, and more). ## 🛠 **Reflect Methods** ### 1. `Reflect.apply()` Forget the complexities of `Function.prototype.apply()`! With `Reflect.apply()`, invoking functions is a breeze. ```js const numbers = [1, 2, 3]; const sum = (a, b, c) => a + b + c; // Using Reflect.apply() const result = Reflect.apply(sum, null, numbers); console.log(result); // Output: 6 ``` ### 2. `Reflect.get()` Tired of the limitations of vanilla property retrieval? `Reflect.get()` offers more control and flexibility. ```js const obj = { x: 42, y: 'hello' }; // Using Reflect.get() const value = Reflect.get(obj, 'x'); console.log(value); // Output: 42 ``` ### 3. `Reflect.set()` Modify properties with pinpoint accuracy, even within complex object hierarchies. ```js const obj = { x: 42 }; // Using Reflect.set() Reflect.set(obj, 'x', 13); console.log(obj.x); // Output: 13 ``` ### 4. `Reflect.defineProperty()` Defining properties with their descriptors has never been easier! ```js const obj = {}; // Using Reflect.defineProperty() Reflect.defineProperty(obj, 'x', { value: 42, writable: false }); console.log(obj.x); // Output: 42 ``` ### 5. `Reflect.deleteProperty()` Wipe properties off the face of your object as if they never existed. ```js const obj = { x: 42 }; // Using Reflect.deleteProperty() Reflect.deleteProperty(obj, 'x'); console.log('x' in obj); // Output: false ``` ### 6. `Reflect.ownKeys()` Discover all the keys an object owns, including Symbols! ```js const obj = { x: 42, [Symbol('key')]: 'symbolValue' }; // Using Reflect.ownKeys() const keys = Reflect.ownKeys(obj); console.log(keys); // Output: ['x', Symbol(key)] ``` ## 🚀 **Why Use Reflect?** By now, you might be asking yourself, "Why should I dive into `Reflect` when there are other ways to manipulate and inspect JavaScript objects?" Great question! Let's unravel the reasons that make `Reflect` a powerful tool in your JavaScript arsenal. ### 1. Functional Paradigm The `Reflect` API offers static methods that embrace the functional programming paradigm, making them first-class citizens that you can pass around in your code. 👉 **Example:** Suppose you want to make property retrieval generic. You can do so with ease. ```js const genericGet = Reflect.get; const value = genericGet(someObject, 'someProperty'); ``` ### 2. Enhanced Error Handling Unlike methods in the `Object` API that often throw errors, `Reflect` methods return a Boolean to indicate success or failure, allowing for more elegant error handling. 👉 **Example:** With `Reflect.set()`, you can check if a property was set successfully and proceed accordingly. ```js if (Reflect.set(obj, 'key', 'value')) { // Property was set successfully } else { // Failed to set the property } ``` ### 3. Proxy Integration `Reflect` and `Proxy` are like two peas in a pod. The methods available in `Reflect` align perfectly with `Proxy` traps, allowing for seamless and straightforward custom behaviors. 👉 **Example:** Creating a logging proxy becomes ridiculously simple. ```js const handler = { get(target, property) { console.log(`Reading property: ${property}`); return Reflect.get(target, property); } }; const proxy = new Proxy(someObject, handler); ``` ### 4. Consistency and Predictability Methods in `Reflect` offer a more consistent API. They always return values (often Booleans) instead of throwing errors, and the parameter orders are predictable, leading to cleaner and more maintainable code. 👉 **Example:** Both `Reflect.get()` and `Reflect.set()` have consistent argument ordering: `target, propertyKey[, receiver]`. ```js Reflect.get(target, property); Reflect.set(target, property, value); ``` ### 5. Intuitive and Self-Documenting `Reflect` methods are often more intuitive and self-documenting than their `Object` counterparts. This readability makes it easier for developers, new and experienced alike, to understand the code. 👉 **Example:** Compare `Reflect.ownKeys(obj)` with `Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj))`. Which one do you find more intuitive? ### 6. Future-Proofing As JavaScript evolves, new methods are more likely to be added to the `Reflect` API, making it a wise choice for long-term projects. For more info don't waste my YouTube video on my [**YouTube Channel**](https://www.youtube.com/@Puppo_92). > 🎬 **Watch / View Embedded Resource:** [https://www.youtube.com/watch?v=gaCvSu3ncbw](https://www.youtube.com/watch?v=gaCvSu3ncbw) ## **Conclusion** And just like that, we've come to the end of our magical journey through the labyrinthine world of JavaScript's `Reflect` API! You're now armed with the tools, tricks, and spells—err methods—to perform object manipulation wizardry that would make Dumbledore proud. Ready to cast your own spells? Grab your keyboard wand, and let's make the JavaScript realm a little more enchanted, one `Reflect` method at a time! Remember, the magic isn't just in the code; it's in you, the coding sorcerer who brings it to life. Until our next spellbinding adventure, code on, wizards! 🚀 _You can find the code of this article_ [in the GitHub repository](https://github.com/Puppo/javascript-you-dont-know/tree/08-reflect-api) > 🎬 **Watch / View Embedded Resource:** [https://dev.to/puppo](https://dev.to/puppo) ---