From 14c42d936576fec093752639f9ef133796ed0419 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 16:41:59 +0500 Subject: [PATCH 01/33] exec: what-are-proxies-in-javascript-used-for --- .../en-US.mdx | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/questions/what-are-proxies-in-javascript-used-for/en-US.mdx b/questions/what-are-proxies-in-javascript-used-for/en-US.mdx index 270b5ce..5869497 100644 --- a/questions/what-are-proxies-in-javascript-used-for/en-US.mdx +++ b/questions/what-are-proxies-in-javascript-used-for/en-US.mdx @@ -8,7 +8,7 @@ In JavaScript, a proxy is an object that acts as an intermediary between an obje Here's a basic example of using a `Proxy` to log every property access: -```js +```js live const myObject = { name: 'John', age: 42, @@ -23,11 +23,13 @@ const handler = { const proxiedObject = new Proxy(myObject, handler); -console.log(proxiedObject.name); // 'John' +console.log(proxiedObject.name); // Someone accessed property "name" +// 'John' -console.log(proxiedObject.age); // 42 +console.log(proxiedObject.age); // Someone accessed property "age" +// 42 ``` Use cases include: @@ -53,7 +55,7 @@ Here are some common use cases and examples of how proxies can be used in JavaSc Proxies can be used to intercept and customize property access on an object. -```js +```js live const target = { message: 'Hello, world!', }; @@ -78,7 +80,7 @@ console.log(proxy.nonExistentProperty); // Property nonExistentProperty does not This is useful for creating wrappers for logging and debugging interactions with an object. -```js +```js live const target = { name: 'Alice', age: 30, @@ -109,7 +111,7 @@ console.log(proxy.age); // Output: Getting property age Proxies can be used to validate property values before they are set on the target object. -```js +```js live const target = { age: 25, }; @@ -136,7 +138,7 @@ Proxies are often used to trigger updates in other parts of your application whe A practical example is JavaScript frameworks like [Vue.js](https://vuejs.org/), where proxies are used to [create reactive systems that automatically update the UI when data changes](https://vuejs.org/guide/extras/reactivity-in-depth.html). -```js +```js live const target = { firstName: 'John', lastName: 'Doe', @@ -164,7 +166,7 @@ Other use cases for access interception include: Proxies can intercept and customize function calls. -```js +```js live const target = function (name) { return `Hello, ${name}!`; }; @@ -188,7 +190,7 @@ This interception can be used to cache and return the result of frequently acces Proxies can be used to dynamically create properties or methods on an object. This is useful for defining properties on-the-fly with default values and avoid storing redundant data in objects. -```js +```js live const target = {}; const handler = { From a869a061cee0f8809a2986e479b47197b94d0ee6 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 16:53:31 +0500 Subject: [PATCH 02/33] exec: how-does-hoisting-affect-function-declarations-and-expressions --- .../en-US.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/questions/how-does-hoisting-affect-function-declarations-and-expressions/en-US.mdx b/questions/how-does-hoisting-affect-function-declarations-and-expressions/en-US.mdx index b7069d1..b874575 100644 --- a/questions/how-does-hoisting-affect-function-declarations-and-expressions/en-US.mdx +++ b/questions/how-does-hoisting-affect-function-declarations-and-expressions/en-US.mdx @@ -6,7 +6,7 @@ title: How does hoisting affect function declarations and expressions? Hoisting in JavaScript means that function declarations are moved to the top of their containing scope during the compile phase, making them available throughout the entire scope. This allows you to call a function before it is defined in the code. However, function expressions are not hoisted in the same way. If you try to call a function expression before it is defined, you will get an error because the variable holding the function is hoisted but not its assignment. -```js +```js live // Function declaration console.log(foo()); // Works fine function foo() { @@ -28,7 +28,7 @@ var bar = function () { Function declarations are hoisted to the top of their containing scope. This means you can call the function before it is defined in the code. -```js +```js live console.log(foo()); // Works fine function foo() { return 'Hello'; @@ -41,7 +41,7 @@ In the example above, the function `foo` is hoisted to the top of its scope, so Function expressions, on the other hand, are not hoisted in the same way. The variable that holds the function is hoisted, but its assignment is not. This means that if you try to call a function expression before it is defined, you will get an error. -```js +```js live console.log(bar()); // Throws TypeError: bar is not a function var bar = function () { return 'Hello'; @@ -57,7 +57,7 @@ It's also important to note the differences in hoisting behavior between `var`, - `var`: The variable is hoisted and initialized with `undefined`. - `let` and `const`: The variables are hoisted but not initialized, leading to a `ReferenceError` if accessed before initialization. -```js +```js live console.log(baz); // undefined var baz = function () { return 'Hello'; From f695bc5227a66e848f2294812ddab1b361449dba Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 17:31:27 +0500 Subject: [PATCH 03/33] exec: what-are-iterators-and-generators-and-what-are-they-used-for --- .../en-US.mdx | 74 ++++++++++++------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/questions/what-are-iterators-and-generators-and-what-are-they-used-for/en-US.mdx b/questions/what-are-iterators-and-generators-and-what-are-they-used-for/en-US.mdx index 83bb42c..835bb5e 100644 --- a/questions/what-are-iterators-and-generators-and-what-are-they-used-for/en-US.mdx +++ b/questions/what-are-iterators-and-generators-and-what-are-they-used-for/en-US.mdx @@ -15,7 +15,7 @@ In JavaScript, iterators and generators are powerful tools for managing sequence Here's an example of an object implementing the iterator interface. -```js +```js live const iterator = { current: 0, last: 5, @@ -37,7 +37,7 @@ while (!result.done) { **Generators** are a special functions that **can pause execution and resume at a later point**. It uses the `function*` syntax and the `yield` keyword to control the flow of execution. When you call a generator function, it doesn't execute completely like a regular function. Instead, it returns an iterator object. Calling the `next()` method on the returned iterator advances the generator to the next `yield` statement, and the value after `yield` becomes the return value of `next()`. -```js +```js live function* numberGenerator() { let num = 0; while (num <= 5) { @@ -74,7 +74,7 @@ Iterators are objects that define a sequence and provide a `next()` method to ac In JavaScript, we can provide a default implementation for iterator by implementing `[Symbol.iterator]()` in any custom object. -```js +```js live // Define a class named Range class Range { // The constructor takes two parameters: start and end @@ -122,7 +122,7 @@ In JavaScript, several built-in objects implement the iterator protocol, meaning 1. **Arrays**: Arrays have a built-in iterator that allows you to iterate over their elements. - ```js + ```js live const array = [1, 2, 3]; const iterator = array[Symbol.iterator](); @@ -138,7 +138,7 @@ In JavaScript, several built-in objects implement the iterator protocol, meaning 2. **Strings**: Strings have a built-in iterator that allows you to iterate over their characters. - ```js + ```js live const string = 'hello'; const iterator = string[Symbol.iterator](); @@ -156,16 +156,20 @@ In JavaScript, several built-in objects implement the iterator protocol, meaning 3. **DOM NodeLists** - ```js + ```js live + // Create a new div and append it to the DOM + const newDiv = document.createElement('div'); + newDiv.id = 'div1'; + document.body.appendChild(newDiv); + const nodeList = document.querySelectorAll('div'); const iterator = nodeList[Symbol.iterator](); - console.log(iterator.next()); // { value: firstDiv, done: false } - console.log(iterator.next()); // { value: secondDiv, done: false } - // ... + console.log(iterator.next()); // { value: HTMLDivElement, done: false } + console.log(iterator.next()); // { value: undefined, done: true } for (const node of nodeList) { - console.log(node); // Logs each
element + console.log(node); // Logs each
element, in this case only div1 } ``` @@ -189,7 +193,7 @@ Generators provide several benefits: We can rewrite our `Range` example to use a generator function: -```js +```js live // Define a class named Range class Range { // The constructor takes two parameters: start and end @@ -225,24 +229,33 @@ for (const number of range) { Generators are well-suited for iterating over data streams, such as fetching data from an API or reading files. This example demonstrates using a generator to fetch data from an API in batches: -```js -async function* fetchDataInBatches(url, batchSize = 10) { +```js live +async function* fetchDataInBatches(url, numBatches = 5, batchSize = 10) { let startIndex = 0; - while (true) { + let currBatch = 0; + + while (currBatch < numBatches) { const response = await fetch( - `${url}?start=${startIndex}&limit=${batchSize}`, + `${url}?_start=${startIndex}&_limit=${batchSize}`, ); const data = await response.json(); if (data.length === 0) break; yield data; startIndex += batchSize; + currBatch += 1; } } -const dataGenerator = fetchDataInBatches('https://api.example.com/data'); -for await (const batch of dataGenerator) { - console.log(batch); +async function fetchAndLogData() { + const dataGenerator = fetchDataInBatches( + 'https://jsonplaceholder.typicode.com/todos', + ); + + for await (const batch of dataGenerator) { + console.log(batch); + } } +fetchAndLogData(); ``` This generator function `fetchDataInBatches` fetches data from an API in batches of a specified size. It yields each batch of data, allowing you to process it before fetching the next batch. This approach can be more memory-efficient than fetching all data at once. @@ -251,22 +264,29 @@ This generator function `fetchDataInBatches` fetches data from an API in batches Generators can be used to implement asynchronous iterators, which are useful for working with asynchronous data sources. This example demonstrates an asynchronous iterator for fetching data from an API: -```js -async function* fetchDataAsyncIterator(url) { - let page = 1; - while (true) { - const response = await fetch(`${url}?page=${page}`); +```js live +async function* fetchDataAsyncIterator(url, pagesToFetch = 3) { + let currPage = 1; + + while (currPage <= pagesToFetch) { + const response = await fetch(`${url}?_page=${currPage}`); const data = await response.json(); if (data.length === 0) break; yield data; - page++; + currPage++; } } -const asyncIterator = fetchDataAsyncIterator('https://api.example.com/data'); -for await (const chunk of asyncIterator) { - console.log(chunk); +async function fetchAndLogData() { + const asyncIterator = fetchDataAsyncIterator( + 'https://jsonplaceholder.typicode.com/todos', + ); + + for await (const chunk of asyncIterator) { + console.log(chunk); + } } +fetchAndLogData(); ``` The generator function `fetchDataAsyncIterator` is an asynchronous iterator that fetches data from an API in pages. It yields each page of data, allowing you to process it before fetching the next page. This approach can be useful for handling large datasets or long-running operations. From b72ad8b4f1019e22b64a2cbf95c2a534141d5f05 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 18:40:25 +0500 Subject: [PATCH 04/33] exec: what-are-javascript-object-property-flags-and-descriptors --- .../en-US.mdx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/questions/what-are-javascript-object-property-flags-and-descriptors/en-US.mdx b/questions/what-are-javascript-object-property-flags-and-descriptors/en-US.mdx index 628a26b..1aba913 100644 --- a/questions/what-are-javascript-object-property-flags-and-descriptors/en-US.mdx +++ b/questions/what-are-javascript-object-property-flags-and-descriptors/en-US.mdx @@ -43,7 +43,7 @@ Property flags are used to specify the behavior of a property. They are set usin Property descriptors provide detailed information about an object's property, encapsulating its value and flags. They are retrieved using `Object.getOwnPropertyDescriptor()` and set using `Object.defineProperty()` -```js +```js live let user = { name: 'John Doe' }; let descriptor = Object.getOwnPropertyDescriptor(user, 'name'); @@ -56,7 +56,7 @@ console.log(descriptor); // {value: "John Doe", writable: true, enumerable: true The `writable` flag specifies whether a property can be written to. When `writable` is `false`, trying to assign value to the property fails silently in non-strict mode, and it throws a `TypeError` in strict mode. -```js +```js live const obj = {}; Object.defineProperty(obj, 'name', { @@ -65,14 +65,15 @@ Object.defineProperty(obj, 'name', { }); console.log(obj.name); // Output: John Doe -obj.name = 'Jane Doe'; // TypeError: Cannot assign to read only property 'name' of object '#' +obj.name = 'Jane Doe'; // This does not change name. Generates TypeError in strict mode +console.log(obj.name); // Output: John Doe (unchanged) ``` ### `enumerable` flag The `enumerable` flag specifies whether a property is enumerable. The `enumerable flag` is set to `true`, which means the property is visible in a `for...in` loop. -```js +```js live const obj = {}; Object.defineProperty(obj, 'name', { @@ -100,7 +101,7 @@ for (const prop in obj1) { The `configurable` flag specifies whether a property can be deleted or its attributes changed. When `configurable` is `false`, trying to delete or change the property fails silently in non-strict mode, and it throws a `TypeError` in strict mode. -```js +```js live const obj = {}; Object.defineProperty(obj, 'name', { @@ -108,7 +109,8 @@ Object.defineProperty(obj, 'name', { value: 'John Doe', }); -delete obj.name; // Output: TypeError: Cannot delete property 'name' of # +delete obj.name; // Does not delete property. Generates TypeError in strict mode +console.log(obj.name); // Output: John Doe (not deleted) ``` ## `Object.seal()` From af145d9f0757e5656e01d97de18afb8606b203b7 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 18:46:50 +0500 Subject: [PATCH 05/33] exec: what-are-javascript-polyfills-for --- questions/what-are-javascript-polyfills-for/en-US.mdx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/questions/what-are-javascript-polyfills-for/en-US.mdx b/questions/what-are-javascript-polyfills-for/en-US.mdx index db2fe65..f54a355 100644 --- a/questions/what-are-javascript-polyfills-for/en-US.mdx +++ b/questions/what-are-javascript-polyfills-for/en-US.mdx @@ -41,7 +41,7 @@ Polyfills detect if a feature or API is missing in a browser and provide a custo For example, let's consider the `Array.prototype.includes()` method, which determines if an array includes a specific element. This method is not supported in older browsers like Internet Explorer 11. To address this, we can use a polyfill: -```js +```js live // Polyfill for Array.prototype.includes() if (!Array.prototype.includes) { Array.prototype.includes = function (searchElement) { @@ -54,6 +54,9 @@ if (!Array.prototype.includes) { return false; }; } + +console.log([1, 2, 3].includes(2)); // true +console.log([1, 2, 3].includes(4)); // false ``` By including this polyfill, we can safely use `Array.prototype.includes()` even in browsers that don't support it natively. From f140b2b25640be0373baec7ef9bbb63cf89b2e21 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 19:13:03 +0500 Subject: [PATCH 06/33] exc: what-is-use-strict-what-are-the-advantages-and-disadvantages-to-using-it --- .../en-US.mdx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/questions/what-is-use-strict-what-are-the-advantages-and-disadvantages-to-using-it/en-US.mdx b/questions/what-is-use-strict-what-are-the-advantages-and-disadvantages-to-using-it/en-US.mdx index 2b75fc8..84a0513 100644 --- a/questions/what-is-use-strict-what-are-the-advantages-and-disadvantages-to-using-it/en-US.mdx +++ b/questions/what-is-use-strict-what-are-the-advantages-and-disadvantages-to-using-it/en-US.mdx @@ -37,7 +37,7 @@ When you use "use strict", it helps you to write cleaner code, like preventing y 1. **Global Scope**: To enable strict mode globally, add the directive at the beginning of the JavaScript file: - ```js + ```js live 'use strict'; // any code in this file will be run in strict mode function add(a, b) { @@ -47,7 +47,7 @@ When you use "use strict", it helps you to write cleaner code, like preventing y 2. **Local Scope**: To enable strict mode within a function, add the directive at the beginning of the function: - ```js + ```js live function myFunction() { 'use strict'; // this will tell JavaScript engine to use strict mode only for the `myFunction` @@ -73,7 +73,7 @@ When you use "use strict", it helps you to write cleaner code, like preventing y 1. Preventing accidental creation of global variables: - ```js + ```js live // Without strict mode function defineNumber() { @@ -83,7 +83,7 @@ When you use "use strict", it helps you to write cleaner code, like preventing y console.log(count); // logs: 123 ``` - ```js + ```js live 'use strict'; // With strict mode function strictFunc() { @@ -96,25 +96,25 @@ When you use "use strict", it helps you to write cleaner code, like preventing y 2. Making assignments which would otherwise silently fail to throw an exception: - ```js + ```js live // Without strict mode NaN = 'foo'; // This fails silently console.log(NaN); // logs: NaN ``` - ```js + ```js live 'use strict'; // With strict mode - NaN = 'foo'; // TypeError: Assignment to read-only properties is not allowed in strict mode + NaN = 'foo'; // Uncaught TypeError: Cannot assign to read only property 'NaN' of object '#' ``` 3. Making attempts to delete undeletable properties throw an error in strict mode: - ```js + ```js live // Without strict mode delete Object.prototype; // This fails silently ``` - ```js + ```js live 'use strict'; // With strict mode delete Object.prototype; // TypeError: Cannot delete property 'prototype' of function Object() { [native code] } ``` From 9947b3a5f2e32d30570fdf9f3a93910e1052aad1 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 19:41:02 +0500 Subject: [PATCH 07/33] exec: what-are-some-techniques-for-reducing-reflows-and-repaints --- .../en-US.mdx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/questions/what-are-some-techniques-for-reducing-reflows-and-repaints/en-US.mdx b/questions/what-are-some-techniques-for-reducing-reflows-and-repaints/en-US.mdx index c0464ef..adf2378 100644 --- a/questions/what-are-some-techniques-for-reducing-reflows-and-repaints/en-US.mdx +++ b/questions/what-are-some-techniques-for-reducing-reflows-and-repaints/en-US.mdx @@ -28,8 +28,11 @@ Grouping multiple DOM changes together can reduce the number of reflows and repa Instead of changing styles directly via JavaScript, use CSS classes: -```js -element.classList.add('new-class'); +```js live +const element = document.createElement('h1'); +element.classList.add('text-center'); + +console.log(element); // Notice that the class has been added. ``` ### Avoid complex CSS selectors @@ -65,9 +68,14 @@ The `will-change` property can hint to the browser about which elements will cha Reading and writing to the DOM separately can prevent layout thrashing: -```js +```js live +// Mock div element +const element = document.createElement('div'); + const height = element.offsetHeight; // Read element.style.height = `${height + 10}px`; // Write + +console.log(element); ``` ## Further reading From 60b9dc7b6d2e62a61bb4ac3b78f5e1d8a78dd973 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 19:50:10 +0500 Subject: [PATCH 08/33] exec: how-can-you-optimize-dom-manipulation-for-better-performance --- .../en-US.mdx | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/questions/how-can-you-optimize-dom-manipulation-for-better-performance/en-US.mdx b/questions/how-can-you-optimize-dom-manipulation-for-better-performance/en-US.mdx index f19d9eb..51fb33b 100644 --- a/questions/how-can-you-optimize-dom-manipulation-for-better-performance/en-US.mdx +++ b/questions/how-can-you-optimize-dom-manipulation-for-better-performance/en-US.mdx @@ -14,33 +14,50 @@ To optimize DOM manipulation for better performance, minimize direct DOM access Accessing the DOM is relatively slow, so try to minimize the number of times you read from or write to the DOM. Instead, store references to elements in variables and work with those. -```js -const element = document.getElementById('myElement'); +```js live +// Creating an element for the example below +const newElement = document.createElement('div'); +newElement.id = 'myElement'; +document.body.appendChild(newElement); + +const element = document.getElementById('myElement'); // Access once +// Then use the reference to edit style element.style.color = 'red'; element.style.backgroundColor = 'blue'; + +console.log(document.body); // Notice the edits ``` ### Batch DOM changes Instead of making multiple changes to the DOM one at a time, batch them together. This reduces the number of reflows and repaints. -```js +```js live +// Creating an element for the example below +const newElement = document.createElement('div'); +newElement.id = 'myElement'; +document.body.appendChild(newElement); + const element = document.getElementById('myElement'); element.style.cssText = 'color: red; background-color: blue;'; + +console.log(document.body); // Notice the edits ``` ### Use `documentFragment` When adding multiple elements to the DOM, use a `documentFragment` to minimize reflows and repaints. -```js +```js live const fragment = document.createDocumentFragment(); for (let i = 0; i < 100; i++) { const newElement = document.createElement('div'); newElement.textContent = `Item ${i}`; fragment.appendChild(newElement); } -document.getElementById('container').appendChild(fragment); +document.body.appendChild(fragment); + +console.log(document.body); // Notice that the divs have been added ``` ### Leverage virtual DOM libraries @@ -76,7 +93,12 @@ requestAnimationFrame(animate); Layout thrashing occurs when you read and write to the DOM repeatedly in a way that forces the browser to recalculate styles and layout multiple times. To avoid this, separate read and write operations. -```js +```js live +// Creating an element for the example below +const newElement = document.createElement('div'); +newElement.id = 'myElement'; +document.body.appendChild(newElement); + const element = document.getElementById('myElement'); const height = element.clientHeight; // Read element.style.height = `${height + 10}px`; // Write From 36fc26620dbf7bcc280ac6f28e899466c88b257e Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 20:22:24 +0500 Subject: [PATCH 09/33] exec: what-is-the-factory-pattern-and-how-is-it-used --- .../en-US.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/questions/what-is-the-factory-pattern-and-how-is-it-used/en-US.mdx b/questions/what-is-the-factory-pattern-and-how-is-it-used/en-US.mdx index 1d47154..0488d66 100644 --- a/questions/what-is-the-factory-pattern-and-how-is-it-used/en-US.mdx +++ b/questions/what-is-the-factory-pattern-and-how-is-it-used/en-US.mdx @@ -8,7 +8,7 @@ The Factory pattern is a design pattern used to create objects without specifyin For example, in JavaScript, you can use a factory function to create different types of objects: -```js +```js live function createAnimal(type) { if (type === 'dog') { return { sound: 'woof' }; @@ -43,7 +43,7 @@ In JavaScript, the Factory pattern can be implemented using factory functions or A factory function is a simple function that returns an object. It can contain logic to decide which type of object to create. -```js +```js live function createAnimal(type) { if (type === 'dog') { return { sound: 'woof' }; @@ -64,7 +64,7 @@ console.log(cat.sound); // Output: meow A factory class can be used to encapsulate the creation logic within a class structure. -```js +```js live class AnimalFactory { createAnimal(type) { if (type === 'dog') { From d0ee5ad12ee87acf0cf92ec3a4cd8637f685c4bb Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 20:24:00 +0500 Subject: [PATCH 10/33] exec: explain-the-observer-pattern-and-its-use-cases --- .../explain-the-observer-pattern-and-its-use-cases/en-US.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/questions/explain-the-observer-pattern-and-its-use-cases/en-US.mdx b/questions/explain-the-observer-pattern-and-its-use-cases/en-US.mdx index a5b8874..a0d28d7 100644 --- a/questions/explain-the-observer-pattern-and-its-use-cases/en-US.mdx +++ b/questions/explain-the-observer-pattern-and-its-use-cases/en-US.mdx @@ -23,7 +23,7 @@ The Observer pattern is a behavioral design pattern that defines a one-to-many d Here is a simple example in JavaScript: -```js +```js live class Subject { constructor() { this.observers = []; From c0e72a3f1d82eecf6d2900c42238a46d318bf3dc Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 20:25:16 +0500 Subject: [PATCH 11/33] exec: what-is-the-module-pattern-and-how-does-it-help-with-encapsulation --- .../en-US.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/questions/what-is-the-module-pattern-and-how-does-it-help-with-encapsulation/en-US.mdx b/questions/what-is-the-module-pattern-and-how-does-it-help-with-encapsulation/en-US.mdx index db342a6..8236090 100644 --- a/questions/what-is-the-module-pattern-and-how-does-it-help-with-encapsulation/en-US.mdx +++ b/questions/what-is-the-module-pattern-and-how-does-it-help-with-encapsulation/en-US.mdx @@ -6,7 +6,7 @@ title: What is the Module pattern and how does it help with encapsulation? The Module pattern in JavaScript is a design pattern used to create self-contained modules of code. It helps with encapsulation by allowing you to define private and public members within a module. Private members are not accessible from outside the module, while public members are exposed through a returned object. This pattern helps in organizing code, avoiding global namespace pollution, and maintaining a clean separation of concerns. -```js +```js live var myModule = (function () { var privateVar = 'I am private'; @@ -40,7 +40,7 @@ The Module pattern typically involves an immediately-invoked function expression Here is a simple example of the Module pattern: -```js +```js live var myModule = (function () { // Private members var privateVar = 'I am private'; From 124b34a4f8fd67191b07837b57b624705a61d15b Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 20:25:53 +0500 Subject: [PATCH 12/33] exec: what-is-the-decorator-pattern-and-how-is-it-used --- .../en-US.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/questions/what-is-the-decorator-pattern-and-how-is-it-used/en-US.mdx b/questions/what-is-the-decorator-pattern-and-how-is-it-used/en-US.mdx index 9941aea..f4d8366 100644 --- a/questions/what-is-the-decorator-pattern-and-how-is-it-used/en-US.mdx +++ b/questions/what-is-the-decorator-pattern-and-how-is-it-used/en-US.mdx @@ -8,7 +8,7 @@ The Decorator pattern is a structural design pattern that allows behavior to be For example, if you have a `Car` class and you want to add features like `GPS` or `Sunroof` without modifying the `Car` class itself, you can create decorators for these features. -```js +```js live class Car { drive() { return 'Driving'; @@ -56,7 +56,7 @@ The Decorator pattern is a structural design pattern that allows you to dynamica In JavaScript, the Decorator pattern can be implemented using classes. Here is an example: -```js +```js live class Car { drive() { return 'Driving'; @@ -96,7 +96,7 @@ console.log(myCarWithGPSAndSunroof.drive()); // "Driving with GPS with Sunroof" Another way to implement the Decorator pattern in JavaScript is by using higher-order functions: -```js +```js live function car() { return { drive: () => 'Driving', From 92d2ed63ada18a6b9044cd93eac5367104966b57 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 20:49:32 +0500 Subject: [PATCH 13/33] exec: what-is-objectseal-for --- questions/what-is-objectseal-for/en-US.mdx | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/questions/what-is-objectseal-for/en-US.mdx b/questions/what-is-objectseal-for/en-US.mdx index adf3a60..18a4b83 100644 --- a/questions/what-is-objectseal-for/en-US.mdx +++ b/questions/what-is-objectseal-for/en-US.mdx @@ -4,15 +4,19 @@ title: What is `Object.seal()` for? ## TL;DR -`Object.seal()` is used to prevent new properties from being added to an object and to mark all existing properties as non-configurable. This means you can still modify the values of existing properties, but you cannot delete them or add new ones. +`Object.seal()` is used to prevent new properties from being added to an object and to mark all existing properties as non-configurable. This means you can still modify the values of existing properties, but you cannot delete them or add new ones. Doing so will throw errors in strict mode but fail silently in non-strict mode. In the following examples, you can uncomment the 'use strict' comment to see this. + +```js live +// 'use strict' -```js const obj = { name: 'John' }; Object.seal(obj); obj.name = 'Jane'; // Allowed -obj.age = 30; // Not allowed -delete obj.name; // Not allowed +obj.age = 30; // Not allowed, throws an error in strict mode +delete obj.name; // Not allowed, throws an error in strict mode + +console.log(obj); // { name: 'Jane } (unchanged) ``` --- @@ -37,7 +41,9 @@ Object.seal(obj); ### Example -```js +```js live +// 'use strict' + const person = { name: 'Alice', age: 25, @@ -51,7 +57,7 @@ person.age = 30; // Allowed person.gender = 'female'; // Not allowed, throws an error in strict mode delete person.name; // Not allowed, throws an error in strict mode -console.log(person); // { name: 'Bob', age: 30 } +console.log(person); // { name: 'Bob', age: 30 } (unchanged) ``` ### Use cases @@ -63,7 +69,7 @@ console.log(person); // { name: 'Bob', age: 30 } You can check if an object is sealed using the `Object.isSealed()` method. -```js +```js live const obj = { name: 'John' }; Object.seal(obj); From b34463808bfdf3533c2349fd4bdfab5b01ec0655 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 20:51:49 +0500 Subject: [PATCH 14/33] exec: what-is-objectpreventextensions-for --- questions/what-is-objectpreventextensions-for/en-US.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/questions/what-is-objectpreventextensions-for/en-US.mdx b/questions/what-is-objectpreventextensions-for/en-US.mdx index a77b209..5a4f489 100644 --- a/questions/what-is-objectpreventextensions-for/en-US.mdx +++ b/questions/what-is-objectpreventextensions-for/en-US.mdx @@ -6,7 +6,7 @@ title: What is `Object.preventExtensions()` for? `Object.preventExtensions()` is a method in JavaScript that prevents new properties from being added to an object. However, it does not affect the deletion or modification of existing properties. This method is useful when you want to ensure that an object remains in a certain shape and no additional properties can be added to it. -```js +```js live const obj = { name: 'John' }; Object.preventExtensions(obj); @@ -36,7 +36,7 @@ Object.preventExtensions(obj); ### Example -```js +```js live const obj = { name: 'John' }; Object.preventExtensions(obj); @@ -54,7 +54,7 @@ console.log(obj.name); // undefined You can check if an object is extensible using the `Object.isExtensible()` method. -```js +```js live const obj = { name: 'John' }; console.log(Object.isExtensible(obj)); // true From 45af4d61bcc4fbf89c9a1b6d620627a332adf10c Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Thu, 20 Mar 2025 20:55:48 +0500 Subject: [PATCH 15/33] exec: what-are-javascript-object-getters-and-setters-for --- .../en-US.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/questions/what-are-javascript-object-getters-and-setters-for/en-US.mdx b/questions/what-are-javascript-object-getters-and-setters-for/en-US.mdx index 6437dbf..ba64882 100644 --- a/questions/what-are-javascript-object-getters-and-setters-for/en-US.mdx +++ b/questions/what-are-javascript-object-getters-and-setters-for/en-US.mdx @@ -10,7 +10,7 @@ Getters and setters are defined using the `get` and `set` keywords, respectively Here's a code example demonstrating the use of getters and setters: -```js +```js live const person = { _name: 'John Doe', // Private property @@ -48,7 +48,7 @@ In JavaScript, getters and setters are special methods that allow you to control - **Getters**: Functions that are invoked whenever you try to access a property using dot notation (e.g., `obj.name`). They provide a way to customize the value that is returned when the property is read. - **Setters**: Functions that are called when you try to assign a value to a property using dot notation with the assignment operator (e.g., `obj.name = "John"`). They allow you to perform actions like data validation, formatting, or side effects before the actual value is stored in the object. -```js +```js live const person = { _firstName: 'John', _lastName: 'Doe', From 583eee010a0e40877fb4895c1b465079b379eab1 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 15:16:30 +0500 Subject: [PATCH 16/33] exec: explain-function-prototype-bind --- .../explain-function-prototype-bind/en-US.mdx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/questions/explain-function-prototype-bind/en-US.mdx b/questions/explain-function-prototype-bind/en-US.mdx index c3bc5b3..9968267 100644 --- a/questions/explain-function-prototype-bind/en-US.mdx +++ b/questions/explain-function-prototype-bind/en-US.mdx @@ -20,7 +20,7 @@ The `bind` method is particularly useful in scenarios where you need to ensure t `bind` was frequently used on legacy React class component methods which were not defined using arrow functions. -```js +```js live const john = { age: 42, getAge: function () { @@ -53,28 +53,28 @@ Here are some common scenarios where `bind` is frequently used: When you pass a function as a callback, the `this` value inside the function can be unpredictable because it is determined by the execution context. Using `bind()` helps ensure that the correct `this` value is maintained. -```js +```js live class Person { - constructor(name) { - this.name = name; + constructor(firstName) { + this.firstName = firstName; } greet() { - console.log(`Hello, my name is ${this.name}`); - }, -}; + console.log(`Hello, my name is ${this.firstName}`); + } +} -const john = new Person('John Doe'); +const john = new Person('John'); // Without bind(), `this` inside the callback will be the global object setTimeout(john.greet, 1000); // Output: "Hello, my name is undefined" // Using bind() to fix the `this` value -setTimeout(john.greet.bind(john), 2000); // Output: "Hello, my name is John Doe" +setTimeout(john.greet.bind(john), 2000); // Output: "Hello, my name is John" ``` You can also use [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) to define class methods for this purpose instead of using `bind`. Arrow functions have the `this` value bound to its lexical context. -```js +```js live class Person { constructor(name) { this.name = name; @@ -92,7 +92,7 @@ setTimeout(john.greet, 1000); // Output: "Hello, my name is John Doe" `bind` can be used to create a new function with some arguments pre-set. This is known as partial application or currying. -```js +```js live function multiply(a, b) { return a * b; } @@ -106,7 +106,7 @@ console.log(multiplyBy5(3)); // Output: 15 `bind` allows you to borrow methods from one object and apply them to another object, even if they were not originally designed to work with that object. This can be handy when you need to reuse functionality across different objects -```js +```js live const person = { name: 'John', greet: function () { From 26a248b0460ae598d09229432bdb498e8ae5aa0d Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 15:18:11 +0500 Subject: [PATCH 17/33] exec: what-are-the-common-pitfalls-of-using-the-this-keyword --- .../en-US.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/questions/what-are-the-common-pitfalls-of-using-the-this-keyword/en-US.mdx b/questions/what-are-the-common-pitfalls-of-using-the-this-keyword/en-US.mdx index 5121e80..0512d9d 100644 --- a/questions/what-are-the-common-pitfalls-of-using-the-this-keyword/en-US.mdx +++ b/questions/what-are-the-common-pitfalls-of-using-the-this-keyword/en-US.mdx @@ -14,7 +14,7 @@ The `this` keyword in JavaScript can be tricky because its value depends on how When you pass a method as a callback, the context of `this` can be lost. For example: -```js +```js live const obj = { value: 42, getValue: function () { @@ -32,7 +32,7 @@ In this case, `this` inside `getValue` is not bound to `obj`. In nested functions, `this` does not refer to the outer function's context: -```js +```js live const obj = { value: 42, getValue: function () { @@ -52,7 +52,7 @@ Here, `this` inside `innerFunction` refers to the global object, not `obj`. Arrow functions do not have their own `this` context; they inherit it from the enclosing scope: -```js +```js live const obj = { value: 42, getValue: () => { @@ -71,7 +71,7 @@ In this example, `this` inside the arrow function refers to the global object, n You can use `.bind()` to explicitly set the context of `this`: -```js +```js live const obj = { value: 42, getValue: function () { @@ -87,7 +87,7 @@ console.log(getValue()); // 42 Arrow functions inherit `this` from the enclosing scope, which can be useful: -```js +```js live const obj = { value: 42, getValue: function () { @@ -105,7 +105,7 @@ console.log(obj.getValue()); // 42 You can store the context in a variable to maintain it in nested functions: -```js +```js live const obj = { value: 42, getValue: function () { From 87e4b84efa4d4bf9a30b68aae50c323d72473bca Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 15:20:10 +0500 Subject: [PATCH 18/33] exec: what-are-the-different-ways-to-make-an-api-call-in-javascript --- .../en-US.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/questions/what-are-the-different-ways-to-make-an-api-call-in-javascript/en-US.mdx b/questions/what-are-the-different-ways-to-make-an-api-call-in-javascript/en-US.mdx index 72b29ae..77e5c01 100644 --- a/questions/what-are-the-different-ways-to-make-an-api-call-in-javascript/en-US.mdx +++ b/questions/what-are-the-different-ways-to-make-an-api-call-in-javascript/en-US.mdx @@ -14,9 +14,9 @@ In JavaScript, you can make API calls using several methods. The most common one `XMLHttpRequest` is the traditional way to make API calls in JavaScript. It is more verbose and requires more code compared to modern methods. -```js +```js live const xhr = new XMLHttpRequest(); -xhr.open('GET', 'https://api.example.com/data', true); +xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos/1', true); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { console.log(JSON.parse(xhr.responseText)); @@ -29,8 +29,8 @@ xhr.send(); `fetch` is a modern and more convenient way to make API calls. It returns a promise, making it easier to handle asynchronous operations. -```js -fetch('https://api.example.com/data') +```js live +fetch('https://jsonplaceholder.typicode.com/todos/1') .then((response) => { if (!response.ok) { throw new Error('Network response was not ok'); From fe05d24a48ebb57d20930a90be495c5be10d0b9b Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 15:28:29 +0500 Subject: [PATCH 19/33] exec: explain-ajax-in-as-much-detail-as-possible --- .../en-US.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/questions/explain-ajax-in-as-much-detail-as-possible/en-US.mdx b/questions/explain-ajax-in-as-much-detail-as-possible/en-US.mdx index 0c2cd34..4f4d1ba 100644 --- a/questions/explain-ajax-in-as-much-detail-as-possible/en-US.mdx +++ b/questions/explain-ajax-in-as-much-detail-as-possible/en-US.mdx @@ -8,7 +8,7 @@ AJAX (Asynchronous JavaScript and XML) facilitates asynchronous communication be **Using `XMLHttpRequest`** -```js +```js live let xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE) { @@ -25,7 +25,7 @@ xhr.send(); **Using `fetch()`** -```js +```js live fetch('https://jsonplaceholder.typicode.com/todos/1') .then((response) => { if (!response.ok) { @@ -49,7 +49,7 @@ Traditionally, AJAX was implemented using the `XMLHttpRequest` API, but the `fet Here's a basic example of how it can be used: -```js +```js live let xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE) { @@ -70,7 +70,7 @@ Alternatively, the `fetch()` API provides a modern, promise-based approach to ma Here's how you can use it: -```js +```js live fetch('https://jsonplaceholder.typicode.com/todos/1') .then((response) => { if (!response.ok) { @@ -100,8 +100,8 @@ In modern browsers, AJAX is done using the `fetch()` API instead of `XMLHTTPRequ 2. **Return a promise**: The `fetch()` function returns a `Promise` that resolves to a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object representing the response from the server. This `Promise needs` to be handled using `.then()` or `async/await`. 3. **Handling the response**: The `Response` object provides methods to define how the body content should be handled, such as `.json()` for parsing JSON data, `.text()` for plain text, `.blob()` for binary data, etc. - ```js - fetch('https://api.example.com/data') + ```js live + fetch('https://jsonplaceholder.typicode.com/todos/1') .then((response) => response.json()) .then((data) => console.log(data)) .catch((error) => console.error('Error:', error)); From 54fbbe45904da494b5b46d75963d3bfd474d58bd Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 15:43:02 +0500 Subject: [PATCH 20/33] exec: what-are-the-differences-between-xmlhttprequest-and-fetch --- .../en-US.mdx | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/questions/what-are-the-differences-between-xmlhttprequest-and-fetch/en-US.mdx b/questions/what-are-the-differences-between-xmlhttprequest-and-fetch/en-US.mdx index c7fc07f..68b2e8e 100644 --- a/questions/what-are-the-differences-between-xmlhttprequest-and-fetch/en-US.mdx +++ b/questions/what-are-the-differences-between-xmlhttprequest-and-fetch/en-US.mdx @@ -26,7 +26,7 @@ Both `XMLHttpRequest` (XHR) and `fetch()` are ways to make asynchronous HTTP req `XMLHttpRequest` is event-driven and requires attaching event listeners to handle response/error states. The basic syntax for creating an `XMLHttpRequest` object and sending a request is as follows: -```js +```js live const xhr = new XMLHttpRequest(); xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos/1', true); xhr.responseType = 'json'; @@ -42,7 +42,7 @@ xhr.send(); `fetch()` provides a more straightforward and intuitive way of making HTTP requests. It is `Promise`-based and returns a promise that resolves with the response or rejects with an error. The basic syntax for making a GET request using `fetch()` is as follows: -```js +```js live fetch('https://jsonplaceholder.typicode.com/todos/1') .then((response) => response.text()) .then((data) => console.log(data)); @@ -111,10 +111,10 @@ fetch('https://jsonplaceholder.typicode.com/todos/1', { `XMLHttpRequest` provides a `responseType` property to set the response format that we are expecting. `responseType` is `'text'` by default but it support types likes `'text'`, `'arraybuffer'`, `'blob'`, `'document'` and `'json'`. -```js +```js live const xhr = new XMLHttpRequest(); xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos/1', true); -xhr.responseType = 'json'; +xhr.responseType = 'json'; // or 'text', 'blob', 'arraybuffer' xhr.onload = function () { if (xhr.status === 200) { console.log(xhr.response); @@ -125,7 +125,7 @@ xhr.send(); On the other hand, `fetch()` provides a unified `Response` object with `then` method for accessing data. -```js +```js live // JSON data fetch('https://jsonplaceholder.typicode.com/todos/1') .then((response) => response.json()) @@ -143,19 +143,28 @@ Both support error handling but `fetch()` provides more flexibility in terms of `XMLHttpRequest` supports error handling using the `onerror` event: -```js +```js live +const xhr = new XMLHttpRequest(); +xhr.open('GET', 'https://jsonplaceholder.typicod.com/todos/1', true); // Typo in URL +xhr.responseType = 'json'; +xhr.onload = function () { + if (xhr.status === 200) { + console.log(xhr.response); + } +}; xhr.onerror = function () { - console.log('Error occurred'); + console.error('Error occurred'); }; +xhr.send(); ``` `fetch()` supports error handling using the `catch()` method on the returned `Promise`: -```js -fetch('https://jsonplaceholder.typicode.com/todos/1') +```js live +fetch('https://jsonplaceholder.typicod.com/todos/1') // Typo in URL .then((response) => response.json()) .then((data) => console.log(data)) - .catch((error) => console.log('Error occurred: ' + error)); + .catch((error) => console.error('Error occurred: ' + error)); ``` ## Caching control @@ -171,11 +180,11 @@ const res = await fetch('https://jsonplaceholder.typicode.com/todos/1', { Other values for the [`cache` option](https://developer.mozilla.org/en-US/docs/Web/API/Request/cache) include `default`, `no-store`, `reload`, `no-cache`, `force-cache`, and `only-if-cached`. -## cancelation +## Cancelation In-flight `XMLHttpRequest`s can be canceled by running the `XMLHttpRequest`'s `abort()` method. An `abort` handler can be attached by assigning to the `.onabort` property if necessary: -```js +```js live const xhr = new XMLHttpRequest(); xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos/1'); xhr.send(); @@ -186,14 +195,14 @@ xhr.abort(); Aborting a `fetch()` requires creating an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) object and passing it to as the `signal` property of the `options` object when calling `fetch()`. -```js +```js live const controller = new AbortController(); const signal = controller.signal; fetch('https://jsonplaceholder.typicode.com/todos/1', { signal }) .then((response) => response.json()) .then((data) => console.log(data)) - .catch((error) => console.log('Error occurred: ' + error)); + .catch((error) => console.error('Error occurred: ' + error)); // Abort request. controller.abort(); From 10e0a71953048f4ee4f7877f30c0fc75d8705fc0 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 15:52:21 +0500 Subject: [PATCH 21/33] exec: what-is-the-purpose-of-the-finally-block --- .../en-US.mdx | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/questions/what-is-the-purpose-of-the-finally-block/en-US.mdx b/questions/what-is-the-purpose-of-the-finally-block/en-US.mdx index 5238e7c..e7b8c5d 100644 --- a/questions/what-is-the-purpose-of-the-finally-block/en-US.mdx +++ b/questions/what-is-the-purpose-of-the-finally-block/en-US.mdx @@ -24,24 +24,33 @@ try { The `finally` block is often used to ensure that certain cleanup code runs regardless of whether an error occurred or not. This is useful for tasks like closing files, releasing resources, or resetting states. -```js -try { - // Attempt to execute code that may throw an error - let data = fetchData(); -} catch (error) { - // Handle any errors that occur - console.error('An error occurred:', error); -} finally { - // Always execute this code - console.log('Cleanup code runs here'); +```js live +async function fetchData() { + try { + const response = await fetch( + 'https://jsonplaceholder.typicode.com/posts/1', + ); + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + const data = await response.json(); + console.log('Fetched data:', data); + } catch (error) { + console.error('An error occurred:', error); + } finally { + console.log('Cleanup code runs here'); + } } + +fetchData(); +// Try creating a typo in the URL to see error handling. ``` ### Guaranteeing execution The `finally` block guarantees that the code within it will execute after the `try` and `catch` blocks have finished. This is true even if a `return` statement is encountered in the `try` or `catch` blocks. -```js +```js live function exampleFunction() { try { return 'Try block'; @@ -59,9 +68,10 @@ console.log(exampleFunction()); // Output: 'Finally block' followed by 'Try bloc When dealing with asynchronous code, the `finally` block can be used to ensure that certain actions are taken after a promise is settled, regardless of its outcome. -```js -fetch('https://api.example.com/data') +```js live +fetch('https://jsonplaceholder.typicode.com/todos/1') .then((response) => response.json()) + .then((res) => console.log(res)) .catch((error) => console.error('Fetch error:', error)) .finally(() => console.log('Fetch attempt finished')); ``` From 51f7e4ccd715cf989f9bd3f17bd25f7c33bf8ee2 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:06:46 +0500 Subject: [PATCH 22/33] exec: how-do-you-abort-a-web-request-using-abortcontrollers --- .../en-US.mdx | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/questions/how-do-you-abort-a-web-request-using-abortcontrollers/en-US.mdx b/questions/how-do-you-abort-a-web-request-using-abortcontrollers/en-US.mdx index 7d7b5bb..f7c7338 100644 --- a/questions/how-do-you-abort-a-web-request-using-abortcontrollers/en-US.mdx +++ b/questions/how-do-you-abort-a-web-request-using-abortcontrollers/en-US.mdx @@ -6,7 +6,7 @@ title: How do you abort a web request using `AbortController` in JavaScript? `AbortController` is used to cancel ongoing asynchronous operations like fetch requests. -```js +```js live const controller = new AbortController(); const signal = controller.signal; @@ -48,7 +48,7 @@ Using `AbortController`s involve the following steps: Here is an example of how to use `AbortController`s with the `fetch()` API: -```js +```js live const controller = new AbortController(); const signal = controller.signal; @@ -74,11 +74,12 @@ controller.abort(); Cancel requests that take too long or are no longer relevant due to user interactions (e.g., user cancels uploading of a huge file). -```js -// HTML: -//
-// -//
+```js live +// HTML: +const btn = document.createElement('button'); +btn.id = 'cancel-button'; +btn.innerHTML = 'Cancel upload'; +document.body.appendChild(btn); const controller = new AbortController(); const signal = controller.signal; @@ -98,6 +99,7 @@ fetch('https://jsonplaceholder.typicode.com/todos/1', { signal }) document.getElementById('cancel-button').addEventListener('click', () => { controller.abort(); }); +document.getElementById('cancel-button').click(); // Simulate clicking the cancel button ``` When you click the "Cancel upload" button, in-flight request will be aborted. @@ -106,7 +108,7 @@ When you click the "Cancel upload" button, in-flight request will be aborted. In scenarios where multiple requests are initiated for the same data, use `AbortController` to prioritize the latest request and abort earlier ones. -```js +```js live let latestController = null; // Keeps track of the latest controller function fetchData(url) { @@ -119,9 +121,8 @@ function fetchData(url) { const signal = controller.signal; fetch(url, { signal }) - .then((response) => { - // Handle successful response - }) + .then((response) => response.json()) + .then((data) => console.log('Fetched data:', data)) .catch((error) => { if (error.name === 'AbortError') { console.log('Request canceled'); @@ -130,6 +131,17 @@ function fetchData(url) { } }); } + +fetchData('https://jsonplaceholder.typicode.com/posts/1'); + +// Simulate race conditions with new requests that quickly cancel the previous one +setTimeout(() => { + fetchData('https://jsonplaceholder.typicode.com/posts/2'); +}, 5); +setTimeout(() => { + fetchData('https://jsonplaceholder.typicode.com/posts/3'); +}, 5); +// Only the last request should (posts/3) will be allowed to complete ``` In this example, when the `fetchData()` function is called multiple times triggering multiple fetch requests, `AbortController`s will cancel all the previous requests except the latest request. This is common in scenarios like type-ahead search or infinite scrolling, where new requests are triggered frequently. From c6156335172a965847fd773eebc6141da69e15ed Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:17:30 +0500 Subject: [PATCH 23/33] exec: explain-the-concept-of-the-web-socket-api --- .../en-US.mdx | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/questions/explain-the-concept-of-the-web-socket-api/en-US.mdx b/questions/explain-the-concept-of-the-web-socket-api/en-US.mdx index cea6b54..d7374b5 100644 --- a/questions/explain-the-concept-of-the-web-socket-api/en-US.mdx +++ b/questions/explain-the-concept-of-the-web-socket-api/en-US.mdx @@ -6,13 +6,15 @@ title: Explain the concept of the Web Socket API The WebSocket API provides a way to open a persistent connection between a client and a server, allowing for real-time, two-way communication. Unlike HTTP, which is request-response based, WebSocket enables full-duplex communication, meaning both the client and server can send and receive messages independently. This is particularly useful for applications like chat apps, live updates, and online gaming. -```js -// Example of creating a WebSocket connection -const socket = new WebSocket('ws://example.com/socket'); +The following example uses Postman's WebSocket echo service to demonstrate how web sockets work. + +```js live +// Postman's echo server that will echo back messages you send +const socket = new WebSocket('wss://ws.postman-echo.com/raw'); // Event listener for when the connection is open socket.addEventListener('open', function (event) { - socket.send('Hello Server!'); + socket.send('Hello Server!'); // Sends the message to the Postman WebSocket server }); // Event listener for when a message is received from the server @@ -42,16 +44,16 @@ The WebSocket API is a technology that provides a way to establish a persistent, ### Example usage -Here is a basic example of how to use the WebSocket API in JavaScript: +Here is a basic example of how to use the WebSocket API in JavaScript, using Postman's WebSocket Echo Service. -```js -// Create a new WebSocket connection -const socket = new WebSocket('ws://example.com/socket'); +```js live +// Postman's echo server that will echo back messages you send +const socket = new WebSocket('wss://ws.postman-echo.com/raw'); // Event listener for when the connection is open socket.addEventListener('open', function (event) { console.log('Connection opened'); - socket.send('Hello Server!'); + socket.send('Hello Server!'); // Sends the message to the Postman WebSocket server }); // Event listener for when a message is received from the server From 9dccf9a368655225372eba3b3969db4412c28451 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:19:53 +0500 Subject: [PATCH 24/33] exec: what-is-the-intl-namespace-object-for --- .../what-is-the-intl-namespace-object-for/en-US.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/questions/what-is-the-intl-namespace-object-for/en-US.mdx b/questions/what-is-the-intl-namespace-object-for/en-US.mdx index 48ffb41..bc28884 100644 --- a/questions/what-is-the-intl-namespace-object-for/en-US.mdx +++ b/questions/what-is-the-intl-namespace-object-for/en-US.mdx @@ -6,7 +6,7 @@ title: What is the `Intl` namespace object for? The `Intl` namespace object in JavaScript is used for internationalization purposes. It provides language-sensitive string comparison, number formatting, and date and time formatting. For example, you can use `Intl.DateTimeFormat` to format dates according to a specific locale: -```js +```js live const date = new Date(); const formatter = new Intl.DateTimeFormat('en-US'); console.log(formatter.format(date)); // Outputs date in 'MM/DD/YYYY' format @@ -22,7 +22,7 @@ The `Intl` namespace object in JavaScript is a part of the ECMAScript Internatio The `Intl.Collator` object is used for comparing strings in a locale-aware manner. This is useful for sorting strings in a way that is consistent with the conventions of a particular language. -```js +```js live const collator = new Intl.Collator('de-DE'); console.log(collator.compare('ä', 'z')); // Outputs a negative number because 'ä' comes before 'z' in German ``` @@ -31,7 +31,7 @@ console.log(collator.compare('ä', 'z')); // Outputs a negative number because ' The `Intl.NumberFormat` object is used for formatting numbers according to the conventions of a specific locale. This includes formatting for currency, percentages, and plain numbers. -```js +```js live const number = 1234567.89; const formatter = new Intl.NumberFormat('de-DE', { style: 'currency', @@ -44,7 +44,7 @@ console.log(formatter.format(number)); // Outputs '1.234.567,89 €' The `Intl.DateTimeFormat` object is used for formatting dates and times according to the conventions of a specific locale. -```js +```js live const date = new Date(); const formatter = new Intl.DateTimeFormat('en-GB', { year: 'numeric', @@ -58,7 +58,7 @@ console.log(formatter.format(date)); // Outputs date in 'DD Month YYYY' format The `Intl.PluralRules` object is used to get the plural form of a number in a specific locale. This is useful for correctly pluralizing words in different languages. -```js +```js live const pluralRules = new Intl.PluralRules('en-US'); console.log(pluralRules.select(1)); // Outputs 'one' console.log(pluralRules.select(2)); // Outputs 'other' From bdab59ea1b5dad68404247b02f36cefd9cda1a15 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:22:57 +0500 Subject: [PATCH 25/33] exec: how-do-currying-and-partial-application-differ-from-each-other --- .../en-US.mdx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/questions/how-do-currying-and-partial-application-differ-from-each-other/en-US.mdx b/questions/how-do-currying-and-partial-application-differ-from-each-other/en-US.mdx index 439ee45..8e4e27a 100644 --- a/questions/how-do-currying-and-partial-application-differ-from-each-other/en-US.mdx +++ b/questions/how-do-currying-and-partial-application-differ-from-each-other/en-US.mdx @@ -16,7 +16,7 @@ Currying is a technique where a function with multiple arguments is transformed #### Example -```js +```js live function add(a) { return function (b) { return function (c) { @@ -25,7 +25,8 @@ function add(a) { }; } -const result = add(1)(2)(3); // 6 +const result = add(1)(2)(3); +console.log(result); // 6 ``` In this example, `add` is a curried function that takes three arguments one at a time. @@ -36,13 +37,14 @@ Partial application is a technique where you fix a few arguments of a function, #### Example -```js +```js live function add(a, b, c) { return a + b + c; } const addOne = add.bind(null, 1); -const result = addOne(2, 3); // 6 +const result = addOne(2, 3); +console.log(result); // 6 ``` In this example, `addOne` is a partially applied function that fixes the first argument of `add` to `1`. From ca69e001e7ab90e03e783c12092c4678d33286f4 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:23:53 +0500 Subject: [PATCH 26/33] exec: what-are-the-benefits-of-using-currying-and-partial-application --- .../en-US.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/questions/what-are-the-benefits-of-using-currying-and-partial-application/en-US.mdx b/questions/what-are-the-benefits-of-using-currying-and-partial-application/en-US.mdx index 7b3a84f..74f85f4 100644 --- a/questions/what-are-the-benefits-of-using-currying-and-partial-application/en-US.mdx +++ b/questions/what-are-the-benefits-of-using-currying-and-partial-application/en-US.mdx @@ -22,7 +22,7 @@ Currying is a technique where a function with multiple arguments is transformed #### Example -```js +```js live function add(a) { return function (b) { return a + b; @@ -45,7 +45,7 @@ Partial application is a technique where you fix a few arguments of a function a #### Example -```js +```js live function multiply(a, b) { return a * b; } From 9b60789e3079f53a639522f6025c00631f0f493d Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:30:33 +0500 Subject: [PATCH 27/33] exec: why-is-extending-built-in-javascript-objects-not-a-good-idea --- .../en-US.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/questions/why-is-extending-built-in-javascript-objects-not-a-good-idea/en-US.mdx b/questions/why-is-extending-built-in-javascript-objects-not-a-good-idea/en-US.mdx index 491fa50..b31aef3 100644 --- a/questions/why-is-extending-built-in-javascript-objects-not-a-good-idea/en-US.mdx +++ b/questions/why-is-extending-built-in-javascript-objects-not-a-good-idea/en-US.mdx @@ -14,7 +14,7 @@ The only time you may want to extend a native object is when you want to create In JavaScript it's very easy to extend a built-in/native object. You can simply extend a built-in object by adding properties and functions to its `prototype`. -```js +```js live String.prototype.reverseString = function () { return this.split('').reverse().join(''); }; From 1387ef026d910eef40fbe59df62601ab49bff780 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:37:18 +0500 Subject: [PATCH 28/33] exec: what-are-the-pros-and-cons-of-using-promises-instead-of-callbacks --- .../en-US.mdx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/questions/what-are-the-pros-and-cons-of-using-promises-instead-of-callbacks/en-US.mdx b/questions/what-are-the-pros-and-cons-of-using-promises-instead-of-callbacks/en-US.mdx index 979460c..15a2a50 100644 --- a/questions/what-are-the-pros-and-cons-of-using-promises-instead-of-callbacks/en-US.mdx +++ b/questions/what-are-the-pros-and-cons-of-using-promises-instead-of-callbacks/en-US.mdx @@ -14,23 +14,23 @@ Promises offer a cleaner alternative to callbacks, helping to avoid callback hel Callback hell, also known as the "pyramid of doom," is a phenomenon that occurs when you have multiple nested callbacks in your code. This can lead to code that is difficult to read, maintain, and debug. Here's an example of callback hell: -```js +```js live function getFirstData(callback) { setTimeout(() => { callback({ id: 1, title: 'First Data' }); - }, 2000); + }, 1000); } function getSecondData(data, callback) { setTimeout(() => { callback({ id: data.id, title: data.title + ' Second Data' }); - }, 2000); + }, 1000); } function getThirdData(data, callback) { setTimeout(() => { callback({ id: data.id, title: data.title + ' Third Data' }); - }, 2000); + }, 1000); } // Callback hell @@ -45,13 +45,13 @@ getFirstData((data) => { Promises address the problem of callback hell by providing a more linear and readable structure for your code. -```js +```js live // Example of sequential asynchronous code using setTimeout and Promises function getFirstData() { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ id: 1, title: 'First Data' }); - }, 2000); + }, 1000); }); } @@ -59,7 +59,7 @@ function getSecondData(data) { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ id: data.id, title: data.title + ' Second Data' }); - }, 2000); + }, 1000); }); } @@ -67,7 +67,7 @@ function getThirdData(data) { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ id: data.id, title: data.title + ' Third Data' }); - }, 2000); + }, 1000); }); } @@ -88,12 +88,12 @@ In the above code example, we use `.then()` method to chain these Promises toget Both `Promise.all()` and callbacks can be used to write parallel asynchronous code. However, `Promise.all()` provides a more concise and readable way to handle multiple Promises, especially when dealing with complex asynchronous workflows. -```js +```js live function getData1() { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ id: 1, title: 'Data 1' }); - }, 2000); + }, 1000); }); } @@ -101,7 +101,7 @@ function getData2() { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ id: 2, title: 'Data 2' }); - }, 2000); + }, 1000); }); } @@ -109,7 +109,7 @@ function getData3() { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ id: 3, title: 'Data 3' }); - }, 2000); + }, 1000); }); } From 69e8a9fbf1ca409fbd3021302b1ce085ec6dc31d Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:39:17 +0500 Subject: [PATCH 29/33] exec: how-is-promiseall-different-from-promiseallsettled --- .../en-US.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/questions/how-is-promiseall-different-from-promiseallsettled/en-US.mdx b/questions/how-is-promiseall-different-from-promiseallsettled/en-US.mdx index e3cee75..910496d 100644 --- a/questions/how-is-promiseall-different-from-promiseallsettled/en-US.mdx +++ b/questions/how-is-promiseall-different-from-promiseallsettled/en-US.mdx @@ -16,7 +16,7 @@ title: How is `Promise.all()` different from `Promise.allSettled()`? #### Example -```js +```js live const promise1 = Promise.resolve(3); const promise2 = 42; const promise3 = new Promise((resolve, reject) => { @@ -36,7 +36,7 @@ In this example, `Promise.all()` resolves with an array of results `[3, 42, 'foo #### Failure case -```js +```js live const promise1 = Promise.resolve(3); const promise2 = Promise.reject('error'); const promise3 = new Promise((resolve, reject) => { @@ -60,7 +60,7 @@ In this example, `Promise.all()` rejects immediately with the reason `'error'` b #### Example -```js +```js live const promise1 = Promise.resolve(3); const promise2 = 42; const promise3 = new Promise((resolve, reject) => { @@ -79,7 +79,7 @@ In this example, `Promise.allSettled()` resolves with an array of result objects #### Failure case -```js +```js live const promise1 = Promise.resolve(3); const promise2 = Promise.reject('error'); const promise3 = new Promise((resolve, reject) => { From 0aa10139f2e129a0cbb10fe8bf7a66b028d545d1 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:42:08 +0500 Subject: [PATCH 30/33] exec: what-is-asyncawait-and-how-does-it-simplify-asynchronous-code --- .../en-US.mdx | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/questions/what-is-asyncawait-and-how-does-it-simplify-asynchronous-code/en-US.mdx b/questions/what-is-asyncawait-and-how-does-it-simplify-asynchronous-code/en-US.mdx index 58f2a0c..b0a7fbc 100644 --- a/questions/what-is-asyncawait-and-how-does-it-simplify-asynchronous-code/en-US.mdx +++ b/questions/what-is-asyncawait-and-how-does-it-simplify-asynchronous-code/en-US.mdx @@ -6,16 +6,19 @@ title: What is async/await and how does it simplify asynchronous code? `async/await` is a modern syntax in JavaScript that simplifies working with promises. By using the `async` keyword before a function, you can use the `await` keyword inside that function to pause execution until a promise is resolved. This makes asynchronous code look and behave more like synchronous code, making it easier to read and maintain. -```js +```js live async function fetchData() { try { - const response = await fetch('https://api.example.com/data'); + const response = await fetch( + 'https://jsonplaceholder.typicode.com/posts/1', + ); const data = await response.json(); console.log(data); } catch (error) { console.error('Error fetching data:', error); } } +fetchData(); ``` --- @@ -30,7 +33,7 @@ async function fetchData() { The `async` keyword is used to declare an asynchronous function. When a function is declared as `async`, it automatically returns a promise. This means you can use the `await` keyword inside it to pause the execution of the function until a promise is resolved. -```js +```js live async function exampleFunction() { return 'Hello, World!'; } @@ -42,16 +45,19 @@ exampleFunction().then(console.log); // Output: Hello, World! The `await` keyword can only be used inside an `async` function. It pauses the execution of the function until the promise is resolved, and then returns the resolved value. If the promise is rejected, it throws an error, which can be caught using a `try...catch` block. -```js +```js live async function fetchData() { try { - const response = await fetch('https://api.example.com/data'); + const response = await fetch( + 'https://jsonplaceholder.typicode.com/posts/1', + ); const data = await response.json(); console.log(data); } catch (error) { console.error('Error fetching data:', error); } } +fetchData(); ``` ### Simplifying asynchronous code @@ -60,8 +66,8 @@ Before `async/await`, handling asynchronous operations often involved chaining m #### Example with promises -```js -fetch('https://api.example.com/data') +```js live +fetch('https://jsonplaceholder.typicode.com/posts/1') .then((response) => response.json()) .then((data) => { console.log(data); @@ -73,32 +79,36 @@ fetch('https://api.example.com/data') #### Example with async/await -```js +```js live async function fetchData() { try { - const response = await fetch('https://api.example.com/data'); + const response = await fetch( + 'https://jsonplaceholder.typicode.com/posts/1', + ); const data = await response.json(); console.log(data); } catch (error) { console.error('Error fetching data:', error); } } +fetchData(); ``` ### Error handling Error handling with `async/await` is more straightforward compared to promises. You can use `try...catch` blocks to handle errors, making the code cleaner and more intuitive. -```js +```js live async function fetchData() { try { - const response = await fetch('https://api.example.com/data'); + const response = await fetch('https://jsonplaceholder.typicod.com/posts/1'); // Typo in URL const data = await response.json(); console.log(data); } catch (error) { console.error('Error fetching data:', error); } } +fetchData(); ``` ## Further reading From 0df5f2f84acf3db7d6cb7e7839c64164ae444985 Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:43:14 +0500 Subject: [PATCH 31/33] exec: explain-the-concept-of-a-microtask-queue --- questions/explain-the-concept-of-a-microtask-queue/en-US.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/questions/explain-the-concept-of-a-microtask-queue/en-US.mdx b/questions/explain-the-concept-of-a-microtask-queue/en-US.mdx index 0e827c8..a60ce88 100644 --- a/questions/explain-the-concept-of-a-microtask-queue/en-US.mdx +++ b/questions/explain-the-concept-of-a-microtask-queue/en-US.mdx @@ -24,7 +24,7 @@ The microtask queue is a part of the JavaScript event loop mechanism. It is a qu Here is an example to illustrate how the microtask queue works: -```js +```js live console.log('Script start'); setTimeout(() => { From 16798176369ef0b0c6f35f30bce30b7b2184499b Mon Sep 17 00:00:00 2001 From: tahachm <97478750+tahachm@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:49:41 +0500 Subject: [PATCH 32/33] partial fix: explain-the-difference-between-mutable-and-immutable-objects --- .../en-US.mdx | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/questions/explain-the-difference-between-mutable-and-immutable-objects/en-US.mdx b/questions/explain-the-difference-between-mutable-and-immutable-objects/en-US.mdx index 0d2248c..974373d 100644 --- a/questions/explain-the-difference-between-mutable-and-immutable-objects/en-US.mdx +++ b/questions/explain-the-difference-between-mutable-and-immutable-objects/en-US.mdx @@ -6,7 +6,7 @@ title: Explain the difference between mutable and immutable objects in JavaScrip **Mutable objects** allow for modification of properties and values after creation, which is the default behavior for most objects. -```js +```js live const mutableObject = { name: 'John', age: 30, @@ -21,7 +21,7 @@ console.log(mutableObject); // Output: { name: 'Jane', age: 30 } **Immutable objects** cannot be directly modified after creation. Its content cannot be changed without creating an entirely new value. -```js +```js live const immutableObject = Object.freeze({ name: 'John', age: 30, @@ -46,7 +46,7 @@ Immutability is a core principle in functional programming but it has lots to of Mutability refers to the ability of an object to have its properties or elements changed after it's created. A mutable object is an object whose state can be modified after it is created. In JavaScript, objects and arrays are mutable by default. They store references to their data in memory. Changing a property or element modifies the original object. Here is an example of a mutable object: -```js +```js live const mutableObject = { name: 'John', age: 30, @@ -63,7 +63,7 @@ console.log(mutableObject); // Output: { name: 'Jane', age: 30 } An immutable object is an object whose state cannot be modified after it is created. Here is an example of an immutable object: -```js +```js live const immutableObject = Object.freeze({ name: 'John', age: 30, @@ -78,7 +78,7 @@ console.log(immutableObject); // Output: { name: 'John', age: 30 } Primitive data types like numbers, strings, booleans, `null`, and `undefined` are inherently immutable. Once assigned a value, you cannot directly modify them. -```js +```js live let name = 'Alice'; name.toUpperCase(); // This won't modify the original name variable console.log(name); // Still prints "Alice" @@ -101,7 +101,7 @@ A common confusion / misunderstanding is that declaring a variable using `const` On the other hand, an immutable object is an object whose state (properties and values) cannot be modified after it is created. This is achieved by using methods like `Object.freeze()` which makes the object immutable by preventing any changes to its properties. -```js +```js live // Using const const person = { name: 'John' }; person = { name: 'Jane' }; // Error: Assignment to constant variable @@ -127,7 +127,7 @@ Here are a few ways to add/simulate different forms of immutability in plain Jav By combining `writable: false` and `configurable: false`, you can essentially create a constant (cannot be changed, redefined or deleted) as an object property, like: -```js +```js live const myObject = {}; Object.defineProperty(myObject, 'number', { value: 42, @@ -143,7 +143,7 @@ console.log(myObject.number); // 42 If you want to prevent an object from having new properties added to it, but otherwise leave the rest of the object's properties alone, call `Object.preventExtensions(...)`: -```js +```js live let myObject = { a: 2, }; @@ -151,7 +151,7 @@ let myObject = { Object.preventExtensions(myObject); myObject.b = 3; -myObject.b; // undefined +console.log(myObject.b); // undefined ``` In non-strict mode, the creation of `b` fails silently. In strict mode, it throws a `TypeError`. @@ -160,7 +160,7 @@ In non-strict mode, the creation of `b` fails silently. In strict mode, it throw `Object.seal()` creates a "sealed" object, which means it takes an existing object and essentially calls `Object.preventExtensions()` on it, but also marks all its existing properties as `configurable: false`. Therefore, not only can you not add any more properties, but you also cannot reconfigure or delete any existing properties, though you can still modify their values. -```js +```js live // Create an object const person = { name: 'John Doe', @@ -181,8 +181,8 @@ person.age = 35; console.log(person); // Output: { name: 'John Doe', age: 35 } -// Try to re-configure an existing property descriptor (this will fail) -Object.defineProperty(person, 'name', { writable: false }); // TypeError: Cannot redefine property: name +// Try to re-configure an existing property descriptor (this will fail silently) +Object.defineProperty(person, 'name', { writable: false }); // Fails silently in non strict mode // Check if the object is sealed console.log(Object.isSealed(person)); // Output: true @@ -202,7 +202,7 @@ Freezing an object does not allow new properties to be added to an object and pr `Object.freeze()` makes the object immutable. However, it is not necessarily constant. `Object.freeze` prevents modifications to the object itself and its direct properties, nested objects within the frozen object can still be modified. -```js +```js live let obj = { user: {}, }; From 2930197cce9b4465393175a1c56f21e16c291567 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 21 Mar 2025 11:53:48 +0000 Subject: [PATCH 33/33] [auto] regenerate table of contents --- README.md | 89 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index bb5d02b..aff1775 100644 --- a/README.md +++ b/README.md @@ -1190,7 +1190,7 @@ AJAX (Asynchronous JavaScript and XML) facilitates asynchronous communication be **Using `XMLHttpRequest`** -```js +```js live let xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE) { @@ -1207,7 +1207,7 @@ xhr.send(); **Using `fetch()`** -```js +```js live fetch('https://jsonplaceholder.typicode.com/todos/1') .then((response) => { if (!response.ok) { @@ -1290,7 +1290,7 @@ These days `fetch()` is preferred for its cleaner syntax and modern features. `AbortController` is used to cancel ongoing asynchronous operations like fetch requests. -```js +```js live const controller = new AbortController(); const signal = controller.signal; @@ -1641,7 +1641,7 @@ In JavaScript, iterators and generators are powerful tools for managing sequence Here's an example of an object implementing the iterator interface. -```js +```js live const iterator = { current: 0, last: 5, @@ -1663,7 +1663,7 @@ while (!result.done) { **Generators** are a special functions that **can pause execution and resume at a later point**. It uses the `function*` syntax and the `yield` keyword to control the flow of execution. When you call a generator function, it doesn't execute completely like a regular function. Instead, it returns an iterator object. Calling the `next()` method on the returned iterator advances the generator to the next `yield` statement, and the value after `yield` becomes the return value of `next()`. -```js +```js live function* numberGenerator() { let num = 0; while (num <= 5) { @@ -1703,7 +1703,7 @@ Generators are powerful for creating iterators on-demand, especially for infinit **Mutable objects** allow for modification of properties and values after creation, which is the default behavior for most objects. -```js +```js live const mutableObject = { name: 'John', age: 30, @@ -1718,7 +1718,7 @@ console.log(mutableObject); // Output: { name: 'Jane', age: 30 } **Immutable objects** cannot be directly modified after creation. Its content cannot be changed without creating an entirely new value. -```js +```js live const immutableObject = Object.freeze({ name: 'John', age: 30, @@ -2003,7 +2003,7 @@ Getters and setters are defined using the `get` and `set` keywords, respectively Here's a code example demonstrating the use of getters and setters: -```js +```js live const person = { _name: 'John Doe', // Private property @@ -2050,7 +2050,7 @@ In JavaScript, a proxy is an object that acts as an intermediary between an obje Here's a basic example of using a `Proxy` to log every property access: -```js +```js live const myObject = { name: 'John', age: 42, @@ -2065,11 +2065,13 @@ const handler = { const proxiedObject = new Proxy(myObject, handler); -console.log(proxiedObject.name); // 'John' +console.log(proxiedObject.name); // Someone accessed property "name" +// 'John' -console.log(proxiedObject.age); // 42 +console.log(proxiedObject.age); // Someone accessed property "age" +// 42 ``` Use cases include: @@ -2442,7 +2444,7 @@ In JavaScript, a proxy is an object that acts as an intermediary between an obje Here's a basic example of using a `Proxy` to log every property access: -```js +```js live const myObject = { name: 'John', age: 42, @@ -2457,11 +2459,13 @@ const handler = { const proxiedObject = new Proxy(myObject, handler); -console.log(proxiedObject.name); // 'John' +console.log(proxiedObject.name); // Someone accessed property "name" +// 'John' -console.log(proxiedObject.age); // 42 +console.log(proxiedObject.age); // Someone accessed property "age" +// 42 ``` Use cases include: @@ -2536,7 +2540,7 @@ The following behavior summarizes the result of accessing the variables before t Hoisting in JavaScript means that function declarations are moved to the top of their containing scope during the compile phase, making them available throughout the entire scope. This allows you to call a function before it is defined in the code. However, function expressions are not hoisted in the same way. If you try to call a function expression before it is defined, you will get an error because the variable holding the function is hoisted but not its assignment. -```js +```js live // Function declaration console.log(foo()); // Works fine function foo() { @@ -2912,7 +2916,7 @@ In JavaScript, iterators and generators are powerful tools for managing sequence Here's an example of an object implementing the iterator interface. -```js +```js live const iterator = { current: 0, last: 5, @@ -2934,7 +2938,7 @@ while (!result.done) { **Generators** are a special functions that **can pause execution and resume at a later point**. It uses the `function*` syntax and the `yield` keyword to control the flow of execution. When you call a generator function, it doesn't execute completely like a regular function. Instead, it returns an iterator object. Calling the `next()` method on the returned iterator advances the generator to the next `yield` statement, and the value after `yield` becomes the return value of `next()`. -```js +```js live function* numberGenerator() { let num = 0; while (num <= 5) { @@ -3512,7 +3516,7 @@ if (obj.hasOwnProperty('key')) { **Mutable objects** allow for modification of properties and values after creation, which is the default behavior for most objects. -```js +```js live const mutableObject = { name: 'John', age: 30, @@ -3527,7 +3531,7 @@ console.log(mutableObject); // Output: { name: 'Jane', age: 30 } **Immutable objects** cannot be directly modified after creation. Its content cannot be changed without creating an entirely new value. -```js +```js live const immutableObject = Object.freeze({ name: 'John', age: 30, @@ -3598,15 +3602,19 @@ console.log(obj); // { name: 'John' } -`Object.seal()` is used to prevent new properties from being added to an object and to mark all existing properties as non-configurable. This means you can still modify the values of existing properties, but you cannot delete them or add new ones. +`Object.seal()` is used to prevent new properties from being added to an object and to mark all existing properties as non-configurable. This means you can still modify the values of existing properties, but you cannot delete them or add new ones. Doing so will throw errors in strict mode but fail silently in non-strict mode. In the following examples, you can uncomment the 'use strict' comment to see this. + +```js live +// 'use strict' -```js const obj = { name: 'John' }; Object.seal(obj); obj.name = 'Jane'; // Allowed -obj.age = 30; // Not allowed -delete obj.name; // Not allowed +obj.age = 30; // Not allowed, throws an error in strict mode +delete obj.name; // Not allowed, throws an error in strict mode + +console.log(obj); // { name: 'Jane } (unchanged) ``` @@ -3623,7 +3631,7 @@ delete obj.name; // Not allowed `Object.preventExtensions()` is a method in JavaScript that prevents new properties from being added to an object. However, it does not affect the deletion or modification of existing properties. This method is useful when you want to ensure that an object remains in a certain shape and no additional properties can be added to it. -```js +```js live const obj = { name: 'John' }; Object.preventExtensions(obj); @@ -3649,7 +3657,7 @@ Getters and setters are defined using the `get` and `set` keywords, respectively Here's a code example demonstrating the use of getters and setters: -```js +```js live const person = { _name: 'John Doe', // Private property @@ -3969,16 +3977,19 @@ Promise.all([promise1, promise2, promise3]).then((values) => { `async/await` is a modern syntax in JavaScript that simplifies working with promises. By using the `async` keyword before a function, you can use the `await` keyword inside that function to pause execution until a promise is resolved. This makes asynchronous code look and behave more like synchronous code, making it easier to read and maintain. -```js +```js live async function fetchData() { try { - const response = await fetch('https://api.example.com/data'); + const response = await fetch( + 'https://jsonplaceholder.typicode.com/posts/1', + ); const data = await response.json(); console.log(data); } catch (error) { console.error('Error fetching data:', error); } } +fetchData(); ``` @@ -5114,7 +5125,7 @@ AJAX (Asynchronous JavaScript and XML) facilitates asynchronous communication be **Using `XMLHttpRequest`** -```js +```js live let xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE) { @@ -5131,7 +5142,7 @@ xhr.send(); **Using `fetch()`** -```js +```js live fetch('https://jsonplaceholder.typicode.com/todos/1') .then((response) => { if (!response.ok) { @@ -5208,7 +5219,7 @@ These days `fetch()` is preferred for its cleaner syntax and modern features. `AbortController` is used to cancel ongoing asynchronous operations like fetch requests. -```js +```js live const controller = new AbortController(); const signal = controller.signal; @@ -5296,13 +5307,15 @@ There are three main types of workers in JavaScript: The WebSocket API provides a way to open a persistent connection between a client and a server, allowing for real-time, two-way communication. Unlike HTTP, which is request-response based, WebSocket enables full-duplex communication, meaning both the client and server can send and receive messages independently. This is particularly useful for applications like chat apps, live updates, and online gaming. -```js -// Example of creating a WebSocket connection -const socket = new WebSocket('ws://example.com/socket'); +The following example uses Postman's WebSocket echo service to demonstrate how web sockets work. + +```js live +// Postman's echo server that will echo back messages you send +const socket = new WebSocket('wss://ws.postman-echo.com/raw'); // Event listener for when the connection is open socket.addEventListener('open', function (event) { - socket.send('Hello Server!'); + socket.send('Hello Server!'); // Sends the message to the Postman WebSocket server }); // Event listener for when a message is received from the server @@ -5385,7 +5398,7 @@ To detect if JavaScript is disabled on a page, you can use the `