diff --git a/README.md b/README.md index aff1775..b7240f0 100644 --- a/README.md +++ b/README.md @@ -853,7 +853,7 @@ In the book ["You Don't Know JS"](https://github.com/getify/You-Dont-Know-JS/tre In simple terms, functions have access to variables that were in their scope at the time of their creation. This is what we call the function's lexical scope. A closure is a function that retains access to these variables even after the outer function has finished executing. This is like the function has a memory of its original environment. -```js +```js live function outerFunction() { const outerVar = 'I am outside of innerFunction'; @@ -1822,7 +1822,7 @@ On the other hand, `WeakSet` only allows objects as elements, and these object e Static class members (properties/methods) has a `static` keyword prepended. Such members cannot be directly accessed on instances of the class. Instead, they're accessed on the class itself. -```js +```js live class Car { static noOfWheels = 4; static compare() { @@ -1855,7 +1855,7 @@ Static members are useful under the following scenarios: `Symbol`s in JavaScript are a new primitive data type introduced in ES6 (ECMAScript 2015). They are unique and immutable identifiers that is primarily for object property keys to avoid name collisions. These values can be created using `Symbol(...)` function, and each `Symbol` value is guaranteed to be unique, even if they have the same key/description. `Symbol` properties are not enumerable in `for...in` loops or `Object.keys()`, making them suitable for creating private/internal object state. -```js +```js live let sym1 = Symbol(); let sym2 = Symbol('myKey'); @@ -2412,7 +2412,7 @@ console.log(combinedObj); // { a: 1, b: 2, c: 3, d: 4 } `Symbol`s in JavaScript are a new primitive data type introduced in ES6 (ECMAScript 2015). They are unique and immutable identifiers that is primarily for object property keys to avoid name collisions. These values can be created using `Symbol(...)` function, and each `Symbol` value is guaranteed to be unique, even if they have the same key/description. `Symbol` properties are not enumerable in `for...in` loops or `Object.keys()`, making them suitable for creating private/internal object state. -```js +```js live let sym1 = Symbol(); let sym2 = Symbol('myKey'); @@ -2568,11 +2568,11 @@ var bar = function () { Hoisting can lead to unexpected behavior in JavaScript because variable and function declarations are moved to the top of their containing scope during the compilation phase. This can result in `undefined` values for variables if they are used before their declaration and can cause confusion with function declarations and expressions. For example: -```js +```js live console.log(a); // undefined var a = 5; -console.log(b); // ReferenceError: b is not defined +console.log(b); // ReferenceError: Cannot access 'b' before initialization let b = 10; ``` @@ -4135,7 +4135,7 @@ Things to note are: The prototype chain is a mechanism in JavaScript that allows objects to inherit properties and methods from other objects. When you try to access a property on an object, JavaScript will first look for the property on the object itself. If it doesn't find it, it will look at the object's prototype, and then the prototype's prototype, and so on, until it either finds the property or reaches the end of the chain, which is `null`. -```js +```js live function Person(name) { this.name = name; } @@ -4401,7 +4401,7 @@ The main takeaway here is that `this` can be changed for a normal function, but Static class members (properties/methods) has a `static` keyword prepended. Such members cannot be directly accessed on instances of the class. Instead, they're accessed on the class itself. -```js +```js live class Car { static noOfWheels = 4; static compare() { @@ -4436,7 +4436,7 @@ In the book ["You Don't Know JS"](https://github.com/getify/You-Dont-Know-JS/tre In simple terms, functions have access to variables that were in their scope at the time of their creation. This is what we call the function's lexical scope. A closure is a function that retains access to these variables even after the outer function has finished executing. This is like the function has a memory of its original environment. -```js +```js live function outerFunction() { const outerVar = 'I am outside of innerFunction'; @@ -5526,12 +5526,13 @@ window.location.replace('https://www.example.com'); To get the query string values of the current page in JavaScript, you can use the `URLSearchParams` object. First, create a `URLSearchParams` instance with `window.location.search`, then use the `get` method to retrieve specific query parameters. For example: -```js +```js live const params = new URLSearchParams(window.location.search); -const value = params.get('key'); +const value = params.get('language'); +console.log(value); ``` -This will give you the value of the query parameter named `key`. +This will give you the value of the query parameter named `language`. If you look at the URL of this page, you can see that the `language` parameter is set to 'js'. @@ -5868,7 +5869,7 @@ try { To create custom error objects in JavaScript, you can extend the built-in `Error` class. This allows you to add custom properties and methods to your error objects. Here's a quick example: -```js +```js live class CustomError extends Error { constructor(message) { super(message); @@ -5928,7 +5929,7 @@ try { Currying is a technique in functional programming where a function that takes multiple arguments is transformed into a series of functions that each take a single argument. This allows for partial application of functions. For example, a function `f(a, b, c)` can be curried into `f(a)(b)(c)`. Here's a simple example in JavaScript: -```js +```js live function add(a) { return function (b) { return function (c) { @@ -5938,8 +5939,13 @@ function add(a) { } const addOne = add(1); +console.log(addOne); // function object + const addOneAndTwo = addOne(2); -const result = addOneAndTwo(3); // result is 6 +console.log(addOneAndTwo); // function object + +const result = addOneAndTwo(3); +console.log(result); // Output: 6 ``` @@ -6033,10 +6039,11 @@ Currying transforms a function with multiple arguments into a sequence of functi `Set`s and `Map`s are built-in JavaScript objects that help manage collections of data. A `Set` is a collection of unique values, while a `Map` is a collection of key-value pairs where keys can be of any type. `Set`s are useful for storing unique items, and `Map`s are useful for associating values with keys. -```js +```js live // Set example -let mySet = new Set([1, 2, 3, 3]); -mySet.add(4); // Set {1, 2, 3, 4} +let mySet = new Set([1, 2, 3, 3]); // Set {1, 2, 3} (duplicate values are not added) +mySet.add(4); +console.log(mySet); // Set {1, 2, 3, 4} // Map example let myMap = new Map(); @@ -6149,7 +6156,7 @@ Both `Map` objects and plain objects in JavaScript can store key-value pairs, bu `Set`s and `Map`s in JavaScript handle equality checks for objects based on reference equality, not deep equality. This means that two objects are considered equal only if they reference the same memory location. For example, if you add two different object literals with the same properties to a `Set`, they will be treated as distinct entries. -```js +```js live const set = new Set(); const obj1 = { a: 1 }; const obj2 = { a: 1 }; @@ -6527,7 +6534,7 @@ Design patterns are reusable solutions to common problems in software design. Th The Singleton pattern ensures that a class has only one instance and provides a global point of access to that instance. This is useful when exactly one object is needed to coordinate actions across the system. In JavaScript, this can be implemented using closures or ES6 classes. -```js +```js live class Singleton { constructor() { if (!Singleton.instance) { @@ -6632,7 +6639,7 @@ myModule.publicMethod(); // Logs: I am private The Prototype pattern is a creational design pattern used to create new objects by copying an existing object, known as the prototype. This pattern is useful when the cost of creating a new object is more expensive than cloning an existing one. In JavaScript, this can be achieved using the `Object.create` method or by using the `prototype` property of a constructor function. -```js +```js live const prototypeObject = { greet() { console.log('Hello, world!'); diff --git a/questions/describe-the-difference-between-a-cookie-sessionstorage-and-localstorage/en-US.mdx b/questions/describe-the-difference-between-a-cookie-sessionstorage-and-localstorage/en-US.mdx index 54dbd83..a77c7bd 100644 --- a/questions/describe-the-difference-between-a-cookie-sessionstorage-and-localstorage/en-US.mdx +++ b/questions/describe-the-difference-between-a-cookie-sessionstorage-and-localstorage/en-US.mdx @@ -100,7 +100,7 @@ The CookieStore API is relatively new and may not be supported in all browsers ( - **Access**: Data is accessible within all tabs and windows of the same origin. - **Security**: All JavaScript on the page have access to values within `localStorage`. -```js +```js live // Set a value in localStorage. localStorage.setItem('key', 'value'); @@ -123,7 +123,7 @@ localStorage.clear(); - **Access**: Data is only accessible within the current tab or window. Different tabs or windows with the same page will have different `sessionStorage` objects. - **Security**: All JavaScript on the same page have access to values within `sessionStorage` for that page. -```js +```js live // Set a value in sessionStorage. sessionStorage.setItem('key', 'value'); diff --git a/questions/explain-the-concept-of-the-prototype-pattern/en-US.mdx b/questions/explain-the-concept-of-the-prototype-pattern/en-US.mdx index 0c8faf7..0fb149a 100644 --- a/questions/explain-the-concept-of-the-prototype-pattern/en-US.mdx +++ b/questions/explain-the-concept-of-the-prototype-pattern/en-US.mdx @@ -6,7 +6,7 @@ title: Explain the concept of the Prototype pattern The Prototype pattern is a creational design pattern used to create new objects by copying an existing object, known as the prototype. This pattern is useful when the cost of creating a new object is more expensive than cloning an existing one. In JavaScript, this can be achieved using the `Object.create` method or by using the `prototype` property of a constructor function. -```js +```js live const prototypeObject = { greet() { console.log('Hello, world!'); @@ -35,7 +35,7 @@ In JavaScript, the Prototype pattern can be implemented using the `Object.create The `Object.create` method creates a new object with the specified prototype object and properties. -```js +```js live const prototypeObject = { greet() { console.log('Hello, world!'); @@ -52,7 +52,7 @@ In this example, `newObject` is created with `prototypeObject` as its prototype. Another way to implement the Prototype pattern in JavaScript is by using constructor functions and the `prototype` property. -```js +```js live function Person(name) { this.name = name; } diff --git a/questions/explain-the-concept-of-the-singleton-pattern/en-US.mdx b/questions/explain-the-concept-of-the-singleton-pattern/en-US.mdx index 35fec65..0d76911 100644 --- a/questions/explain-the-concept-of-the-singleton-pattern/en-US.mdx +++ b/questions/explain-the-concept-of-the-singleton-pattern/en-US.mdx @@ -6,7 +6,7 @@ title: Explain the concept of the Singleton pattern The Singleton pattern ensures that a class has only one instance and provides a global point of access to that instance. This is useful when exactly one object is needed to coordinate actions across the system. In JavaScript, this can be implemented using closures or ES6 classes. -```js +```js live class Singleton { constructor() { if (!Singleton.instance) { @@ -40,7 +40,7 @@ There are several ways to implement the Singleton pattern in JavaScript. Here ar #### Using closures -```js +```js live const Singleton = (function () { let instance; @@ -67,7 +67,7 @@ console.log(instance1 === instance2); // true #### Using ES6 classes -```js +```js live class Singleton { constructor() { if (!Singleton.instance) { diff --git a/questions/how-can-you-create-custom-error-objects/en-US.mdx b/questions/how-can-you-create-custom-error-objects/en-US.mdx index f11db4f..b718874 100644 --- a/questions/how-can-you-create-custom-error-objects/en-US.mdx +++ b/questions/how-can-you-create-custom-error-objects/en-US.mdx @@ -6,7 +6,7 @@ title: How can you create custom error objects? To create custom error objects in JavaScript, you can extend the built-in `Error` class. This allows you to add custom properties and methods to your error objects. Here's a quick example: -```js +```js live class CustomError extends Error { constructor(message) { super(message); @@ -43,7 +43,7 @@ class CustomError extends Error { You can add custom properties to your custom error class to provide more context about the error. -```js +```js live class CustomError extends Error { constructor(message, errorCode) { super(message); @@ -65,7 +65,7 @@ try { You can also add custom methods to your custom error class to handle specific error-related logic. -```js +```js live class CustomError extends Error { constructor(message, errorCode) { super(message); @@ -89,7 +89,15 @@ try { You can use the `instanceof` operator to check if an error is an instance of your custom error class. -```js +```js live +class CustomError extends Error { + constructor(message, errorCode) { + super(message); + this.name = 'CustomError'; + this.errorCode = errorCode; + } +} + try { throw new CustomError('This is a custom error message', 404); } catch (error) { diff --git a/questions/how-do-sets-and-maps-handle-equality-checks-for-objects/en-US.mdx b/questions/how-do-sets-and-maps-handle-equality-checks-for-objects/en-US.mdx index 73971da..6691303 100644 --- a/questions/how-do-sets-and-maps-handle-equality-checks-for-objects/en-US.mdx +++ b/questions/how-do-sets-and-maps-handle-equality-checks-for-objects/en-US.mdx @@ -6,7 +6,7 @@ title: How do `Set`s and `Map`s handle equality checks for objects? `Set`s and `Map`s in JavaScript handle equality checks for objects based on reference equality, not deep equality. This means that two objects are considered equal only if they reference the same memory location. For example, if you add two different object literals with the same properties to a `Set`, they will be treated as distinct entries. -```js +```js live const set = new Set(); const obj1 = { a: 1 }; const obj2 = { a: 1 }; @@ -29,7 +29,7 @@ In JavaScript, `Set`s and `Map`s use reference equality to determine if two obje When you add objects to a `Set`, the `Set` will only consider them equal if they are the same object reference. -```js +```js live const set = new Set(); const obj1 = { a: 1 }; const obj2 = { a: 1 }; @@ -46,7 +46,7 @@ In this example, `obj1` and `obj2` have the same properties, but they are differ Similarly, when you use objects as keys in a `Map`, the `Map` will only consider them equal if they are the same object reference. -```js +```js live const map = new Map(); const obj1 = { a: 1 }; const obj2 = { a: 1 }; diff --git a/questions/how-do-you-get-the-query-string-values-of-the-current-page-in-javascript/en-US.mdx b/questions/how-do-you-get-the-query-string-values-of-the-current-page-in-javascript/en-US.mdx index e5ceca9..f3def3d 100644 --- a/questions/how-do-you-get-the-query-string-values-of-the-current-page-in-javascript/en-US.mdx +++ b/questions/how-do-you-get-the-query-string-values-of-the-current-page-in-javascript/en-US.mdx @@ -6,12 +6,13 @@ title: How do you get the query string values of the current page in JavaScript? To get the query string values of the current page in JavaScript, you can use the `URLSearchParams` object. First, create a `URLSearchParams` instance with `window.location.search`, then use the `get` method to retrieve specific query parameters. For example: -```js +```js live const params = new URLSearchParams(window.location.search); -const value = params.get('key'); +const value = params.get('language'); +console.log(value); ``` -This will give you the value of the query parameter named `key`. +This will give you the value of the query parameter named `language`. If you look at the URL of this page, you can see that the `language` parameter is set to 'js'. --- @@ -24,11 +25,14 @@ The `URLSearchParams` interface provides an easy way to work with query strings. 1. **Create a `URLSearchParams` instance**: Use `window.location.search` to get the query string part of the URL. 2. **Retrieve specific query parameters**: Use the `get` method to get the value of a specific query parameter. -```js +```js live const params = new URLSearchParams(window.location.search); -const value = params.get('key'); // Replace 'key' with the actual query parameter name +const value = params.get('key'); // Replace 'key' with the actual query parameter name (try 'language' or 'tab' for this page) +console.log(value); ``` +If the query parameter does not exist, the `get` method returns `null`. + ### Example Consider a URL like `https://example.com?page=2&sort=asc`. To get the values of `page` and `sort`: @@ -50,22 +54,26 @@ const values = params.getAll('key'); // Returns an array of values ### Checking for the existence of a parameter -You can use the `has` method to check if a query parameter exists: +You can use the `has` method to check if a query parameter exists. Try to check for the query parameters present in the URL of this page. -```js +```js live const params = new URLSearchParams(window.location.search); -const hasPage = params.has('page'); // true or false +console.log(params.has('page')); // false +console.log(params.has('language')); // true +console.log(params.has('tab')); // true ``` ### Iterating over all parameters You can iterate over all query parameters using the `forEach` method: -```js +```js live const params = new URLSearchParams(window.location.search); params.forEach((value, key) => { console.log(`${key}: ${value}`); }); +// language: js +// tab: quiz ``` ## Further reading diff --git a/questions/how-do-you-handle-errors-using-trycatch-blocks/en-US.mdx b/questions/how-do-you-handle-errors-using-trycatch-blocks/en-US.mdx index f535d9b..1b29074 100644 --- a/questions/how-do-you-handle-errors-using-trycatch-blocks/en-US.mdx +++ b/questions/how-do-you-handle-errors-using-trycatch-blocks/en-US.mdx @@ -38,7 +38,12 @@ try { Here is an example of using `try...catch` to handle errors: -```js +```js live +function riskyOperation() { + const invalidJsonString = '{"name": "John}'; // Try changing this to a valid JSON string + return JSON.parse(invalidJsonString); +} + try { let result = riskyOperation(); console.log(result); @@ -59,15 +64,21 @@ try { You can nest `try...catch` blocks to handle different levels of errors: -```js +```js live +function anotherRiskyOperation() { + const person = undefined; + console.log(person.name); +} + try { try { - let result = anotherRiskyOperation(); - console.log(result); + anotherRiskyOperation(); } catch (innerError) { + // Error (if any) for anotherRiskyOperation caught here console.error('Inner error:', innerError.message); } } catch (outerError) { + // Inner error does not reach here console.error('Outer error:', outerError.message); } ``` @@ -76,11 +87,21 @@ try { You can re-throw an error from the `catch` block if you want it to be handled by an outer `try...catch` block: -```js +```js live +function yetAnotherRiskyOperation() { + const numerator = 10; + const denominator = 0; + if (denominator === 0) { + throw new Error('Cannot divide by zero'); + } + + return numerator / denominator; +} + try { try { - let result = yetAnotherRiskyOperation(); - console.log(result); + const result = yetAnotherRiskyOperation(); + console.log('Divisinon result:', result); } catch (innerError) { console.error('Inner error:', innerError.message); throw innerError; // Re-throw the error @@ -95,6 +116,7 @@ try { The `finally` block is useful for cleanup tasks, such as closing a file or releasing resources: ```js +// openFile() and closeFile() are custom implementations try { let file = openFile('example.txt'); // Perform operations on the file diff --git a/questions/what-are-design-patterns-and-why-are-they-useful/en-US.mdx b/questions/what-are-design-patterns-and-why-are-they-useful/en-US.mdx index d3d3156..deaec83 100644 --- a/questions/what-are-design-patterns-and-why-are-they-useful/en-US.mdx +++ b/questions/what-are-design-patterns-and-why-are-they-useful/en-US.mdx @@ -34,7 +34,7 @@ Design patterns are typically categorized into three main types: The Singleton pattern ensures that a class has only one instance and provides a global point of access to it. Here is a simple implementation in JavaScript: -```js +```js live class Singleton { constructor() { if (Singleton.instance) { diff --git a/questions/what-are-sets-and-maps-and-how-are-they-used/en-US.mdx b/questions/what-are-sets-and-maps-and-how-are-they-used/en-US.mdx index 3202702..3783b7a 100644 --- a/questions/what-are-sets-and-maps-and-how-are-they-used/en-US.mdx +++ b/questions/what-are-sets-and-maps-and-how-are-they-used/en-US.mdx @@ -6,10 +6,11 @@ title: What are `Set`s and `Map`s and how are they used? `Set`s and `Map`s are built-in JavaScript objects that help manage collections of data. A `Set` is a collection of unique values, while a `Map` is a collection of key-value pairs where keys can be of any type. `Set`s are useful for storing unique items, and `Map`s are useful for associating values with keys. -```js +```js live // Set example -let mySet = new Set([1, 2, 3, 3]); -mySet.add(4); // Set {1, 2, 3, 4} +let mySet = new Set([1, 2, 3, 3]); // Set {1, 2, 3} (duplicate values are not added) +mySet.add(4); +console.log(mySet); // Set {1, 2, 3, 4} // Map example let myMap = new Map(); @@ -30,7 +31,7 @@ A `Set` is a collection of values where each value must be unique. It is similar You can create a `Set` using the `Set` constructor: -```js +```js live let mySet = new Set([1, 2, 3, 3]); console.log(mySet); // Set {1, 2, 3} ``` @@ -45,7 +46,7 @@ console.log(mySet); // Set {1, 2, 3} ### Example usage -```js +```js live let mySet = new Set(); mySet.add(1); mySet.add(2); @@ -68,10 +69,11 @@ A `Map` is a collection of key-value pairs where keys can be of any type, includ You can create a `Map` using the `Map` constructor: -```js +```js live let myMap = new Map(); myMap.set('key1', 'value1'); myMap.set('key2', 'value2'); +console.log(myMap); // Map { key1: "value1", key2: "value2" } ``` ### Common methods @@ -85,7 +87,7 @@ myMap.set('key2', 'value2'); ### Example usage -```js +```js live let myMap = new Map(); myMap.set('key1', 'value1'); myMap.set('key2', 'value2'); diff --git a/questions/what-are-symbols-used-for/en-US.mdx b/questions/what-are-symbols-used-for/en-US.mdx index 6b176b3..2334bab 100644 --- a/questions/what-are-symbols-used-for/en-US.mdx +++ b/questions/what-are-symbols-used-for/en-US.mdx @@ -6,7 +6,7 @@ title: What are `Symbol`s used for in JavaScript? `Symbol`s in JavaScript are a new primitive data type introduced in ES6 (ECMAScript 2015). They are unique and immutable identifiers that is primarily for object property keys to avoid name collisions. These values can be created using `Symbol(...)` function, and each `Symbol` value is guaranteed to be unique, even if they have the same key/description. `Symbol` properties are not enumerable in `for...in` loops or `Object.keys()`, making them suitable for creating private/internal object state. -```js +```js live let sym1 = Symbol(); let sym2 = Symbol('myKey'); @@ -38,7 +38,7 @@ Symbols in JavaScript are a unique and immutable data type used primarily for ob `Symbol`s can be created using the `Symbol()` function: -```js +```js live const sym1 = Symbol(); const sym2 = Symbol('uniqueKey'); @@ -52,7 +52,7 @@ console.log(sym1 === sym2); // false, because each symbol is unique `Symbol`s can be used to add properties to an object without risk of name collision: -```js +```js live const obj = {}; const sym = Symbol('uniqueKey'); @@ -66,7 +66,7 @@ console.log(obj[sym]); // "value" - This makes them suitable for creating private/internal object state. - Use` Object.getOwnPropertySymbols(obj)` to get all symbol properties on an object. -```js +```js live const mySymbol = Symbol('privateProperty'); const obj = { name: 'John', @@ -81,7 +81,7 @@ console.log(obj[mySymbol]); // Output: 42 You can create global `Symbol`s using `Symbol.for('key')`, which creates a new `Symbol` in the global registry if it doesn't exist, or returns the existing one. This allows you to reuse `Symbol`s across different parts of your code base or even across different code bases. -```js +```js live const globalSym1 = Symbol.for('globalKey'); const globalSym2 = Symbol.for('globalKey'); @@ -101,7 +101,7 @@ JavaScript includes several built-in `Symbol`s, referred as well-known `Symbol`s ### `Symbol.iterator` -```js +```js live let iterable = { [Symbol.iterator]() { let step = 0; @@ -124,7 +124,7 @@ for (let value of iterable) { ### `Symbol.toStringTag` -```js +```js live let myObj = { [Symbol.toStringTag]: 'MyCustomObject', }; diff --git a/questions/what-are-the-differences-between-map-set-and-weakmap-weakset/en-US.mdx b/questions/what-are-the-differences-between-map-set-and-weakmap-weakset/en-US.mdx index 3b788b6..6ee55a3 100644 --- a/questions/what-are-the-differences-between-map-set-and-weakmap-weakset/en-US.mdx +++ b/questions/what-are-the-differences-between-map-set-and-weakmap-weakset/en-US.mdx @@ -57,7 +57,7 @@ The key differences between `Map`/`Set` and `WeakMap`/`WeakSet` in JavaScript ar In a chat application, you might want to track which user objects are currently active without preventing garbage collection when the user logs out or the session expires. We use a `WeakSet` to track active user objects. When a user logs out or their session expires, the user object can be garbage-collected if there are no other references to it. -```js +```js live const activeUsers = new WeakSet(); // Function to mark a user as active @@ -91,7 +91,7 @@ console.log(isUserActive(user1)); // false `WeakSet` is provides a way of guarding against circular data structures by tracking which objects have already been processed. -```js +```js live // Create a WeakSet to track visited objects const visited = new WeakSet(); diff --git a/questions/what-are-the-different-types-of-errors-in-javascript/en-US.mdx b/questions/what-are-the-different-types-of-errors-in-javascript/en-US.mdx index 021db55..50a4048 100644 --- a/questions/what-are-the-different-types-of-errors-in-javascript/en-US.mdx +++ b/questions/what-are-the-different-types-of-errors-in-javascript/en-US.mdx @@ -16,7 +16,7 @@ Syntax errors occur when the code does not follow the rules of the JavaScript la #### Example -```js +```js live console.log("Hello, world!; // Missing closing quote and parenthesis ``` @@ -26,9 +26,9 @@ Runtime errors, also known as exceptions, occur during the execution of the code #### Example -```js +```js live let obj = null; -console.log(obj.property); // TypeError: Cannot read property 'property' of null +console.log(obj.property); // TypeError: Cannot read properties of null (reading 'property') ``` ### Logical errors @@ -37,12 +37,15 @@ Logical errors are mistakes in the code's logic that lead to incorrect results. #### Example -```js -let total = 0; -for (let i = 1; i <= 10; i++) { - total += i; +```js live +let isAdmin = false; + +if ((isAdmin = true)) { + // Wrong: Assignment instead of comparison + console.log('Access granted'); // Access granted even though isAdmin was falsy +} else { + console.log('Access denied'); } -console.log(total); // Incorrectly expecting the sum of even numbers only ``` ## Further reading diff --git a/questions/what-are-the-potential-issues-caused-by-hoisting/en-US.mdx b/questions/what-are-the-potential-issues-caused-by-hoisting/en-US.mdx index 647ba70..5d69cd2 100644 --- a/questions/what-are-the-potential-issues-caused-by-hoisting/en-US.mdx +++ b/questions/what-are-the-potential-issues-caused-by-hoisting/en-US.mdx @@ -6,11 +6,11 @@ title: What are the potential issues caused by hoisting? Hoisting can lead to unexpected behavior in JavaScript because variable and function declarations are moved to the top of their containing scope during the compilation phase. This can result in `undefined` values for variables if they are used before their declaration and can cause confusion with function declarations and expressions. For example: -```js +```js live console.log(a); // undefined var a = 5; -console.log(b); // ReferenceError: b is not defined +console.log(b); // ReferenceError: Cannot access 'b' before initialization let b = 10; ``` @@ -22,7 +22,7 @@ let b = 10; When using `var`, the variable is hoisted to the top of its scope but not initialized. This means you can reference the variable before its declaration, but it will be `undefined` until the assignment is executed. -```js +```js live console.log(a); // undefined var a = 5; ``` @@ -31,8 +31,8 @@ var a = 5; Variables declared with `let` and `const` are also hoisted, but they are not initialized. Accessing them before their declaration results in a `ReferenceError` due to the temporal dead zone. -```js -console.log(b); // ReferenceError: b is not defined +```js live +console.log(b); // ReferenceError: Cannot access 'b' before initialization let b = 10; ``` @@ -40,7 +40,7 @@ let b = 10; Function declarations are hoisted entirely, meaning you can call the function before its declaration. However, function expressions are not hoisted in the same way, leading to potential `TypeError` if called before they are defined. -```js +```js live foo(); // Works fine function foo() { console.log('Hello'); @@ -56,7 +56,7 @@ var bar = function () { Using `var` can lead to unintentional redeclarations, which can cause bugs that are hard to track down. -```js +```js live var x = 1; if (true) { var x = 2; // Same variable as above diff --git a/questions/what-are-the-potential-pitfalls-of-using-closures/en-US.mdx b/questions/what-are-the-potential-pitfalls-of-using-closures/en-US.mdx index d34f5e8..42dd6ed 100644 --- a/questions/what-are-the-potential-pitfalls-of-using-closures/en-US.mdx +++ b/questions/what-are-the-potential-pitfalls-of-using-closures/en-US.mdx @@ -14,7 +14,7 @@ Closures can lead to memory leaks if not managed properly, especially when they Closures can cause memory leaks if they capture variables that are no longer needed. This happens because closures keep references to the variables in their scope, preventing the garbage collector from freeing up memory. -```js +```js live function createClosure() { let largeArray = new Array(1000000).fill('some data'); return function () { @@ -24,13 +24,14 @@ function createClosure() { let closure = createClosure(); // The largeArray is still in memory because the closure keeps a reference to it +closure(); // Output: 'some data' ``` ### Debugging complexity Closures can make debugging more difficult due to the complexity of the scope chain. When a bug occurs, it can be challenging to trace the source of the problem through multiple layers of nested functions and scopes. -```js +```js live function outerFunction() { let outerVar = 'I am outside!'; @@ -42,14 +43,14 @@ function outerFunction() { } let myFunction = outerFunction(); -myFunction(); +myFunction(); // Output: 'I am outside!' ``` ### Performance issues Overusing closures or using them inappropriately can lead to performance issues. Since closures keep references to variables in their scope, they can prevent garbage collection, leading to increased memory usage and potential slowdowns. -```js +```js live function createManyClosures() { let counter = 0; @@ -57,6 +58,8 @@ function createManyClosures() { (function () { counter++; })(); + // The closure is executed immediately, but it still holds onto the reference to the `counter` variable + // This prevents the counter from being garbage collected } console.log(counter); // This can be inefficient @@ -69,7 +72,7 @@ createManyClosures(); Closures can lead to unintended variable sharing, especially in loops. This happens when all closures share the same reference to a variable, leading to unexpected behavior. -```js +```js live function createFunctions() { let functions = []; @@ -90,7 +93,7 @@ funcs[2](); // 3 To avoid this, use `let` instead of `var` to create a new binding for each iteration: -```js +```js live function createFunctions() { let functions = []; diff --git a/questions/what-is-a-closure-and-how-why-would-you-use-one/en-US.mdx b/questions/what-is-a-closure-and-how-why-would-you-use-one/en-US.mdx index 3e2c961..420bcc4 100644 --- a/questions/what-is-a-closure-and-how-why-would-you-use-one/en-US.mdx +++ b/questions/what-is-a-closure-and-how-why-would-you-use-one/en-US.mdx @@ -10,7 +10,7 @@ In the book ["You Don't Know JS"](https://github.com/getify/You-Dont-Know-JS/tre In simple terms, functions have access to variables that were in their scope at the time of their creation. This is what we call the function's lexical scope. A closure is a function that retains access to these variables even after the outer function has finished executing. This is like the function has a memory of its original environment. -```js +```js live function outerFunction() { const outerVar = 'I am outside of innerFunction'; @@ -49,7 +49,7 @@ Here's how closures work: With ES6, closures can be created using arrow functions, which provide a more concise syntax and lexically bind the `this` value. Here's an example: -```js +```js live const createCounter = () => { let count = 0; return () => { diff --git a/questions/what-is-currying-and-how-does-it-work/en-US.mdx b/questions/what-is-currying-and-how-does-it-work/en-US.mdx index 2913887..4adb1ab 100644 --- a/questions/what-is-currying-and-how-does-it-work/en-US.mdx +++ b/questions/what-is-currying-and-how-does-it-work/en-US.mdx @@ -6,7 +6,7 @@ title: What is currying and how does it work? Currying is a technique in functional programming where a function that takes multiple arguments is transformed into a series of functions that each take a single argument. This allows for partial application of functions. For example, a function `f(a, b, c)` can be curried into `f(a)(b)(c)`. Here's a simple example in JavaScript: -```js +```js live function add(a) { return function (b) { return function (c) { @@ -16,8 +16,13 @@ function add(a) { } const addOne = add(1); +console.log(addOne); // function object + const addOneAndTwo = addOne(2); -const result = addOneAndTwo(3); // result is 6 +console.log(addOneAndTwo); // function object + +const result = addOneAndTwo(3); +console.log(result); // Output: 6 ``` --- @@ -37,7 +42,7 @@ Currying is a functional programming technique where a function with multiple ar Here's a simple example to illustrate currying in JavaScript: -```js +```js live // Non-curried function function add(a, b, c) { return a + b + c; @@ -54,8 +59,13 @@ function curriedAdd(a) { // Using the curried function const addOne = curriedAdd(1); +console.log(addOne); // function object + const addOneAndTwo = addOne(2); -const result = addOneAndTwo(3); // result is 6 +console.log(addOneAndTwo); // function object + +const result = addOneAndTwo(3); +console.log(result); // Output: 6 ``` ### Benefits of currying @@ -68,7 +78,7 @@ const result = addOneAndTwo(3); // result is 6 Consider a function that calculates the volume of a rectangular prism: -```js +```js live function volume(length, width, height) { return length * width * height; } @@ -85,19 +95,21 @@ function curriedVolume(length) { // Using the curried function const volumeWithLength5 = curriedVolume(5); const volumeWithLength5AndWidth4 = volumeWithLength5(4); -const result = volumeWithLength5AndWidth4(3); // result is 60 +const result = volumeWithLength5AndWidth4(3); +console.log(result); // Output: 60 ``` ### Currying with arrow functions You can also use arrow functions to make the syntax more concise: -```js +```js live const curriedAdd = (a) => (b) => (c) => a + b + c; const addOne = curriedAdd(1); const addOneAndTwo = addOne(2); -const result = addOneAndTwo(3); // result is 6 +const result = addOneAndTwo(3); +console.log(result); // Output: 6 ``` ## Further reading diff --git a/questions/what-is-the-difference-between-a-map-object-and-a-plain-object-in-javascript/en-US.mdx b/questions/what-is-the-difference-between-a-map-object-and-a-plain-object-in-javascript/en-US.mdx index 772e607..42c6996 100644 --- a/questions/what-is-the-difference-between-a-map-object-and-a-plain-object-in-javascript/en-US.mdx +++ b/questions/what-is-the-difference-between-a-map-object-and-a-plain-object-in-javascript/en-US.mdx @@ -26,20 +26,22 @@ In JavaScript, `Map` objects and a plain object (also known as a "POJO" or "plai A plain object is a basic JavaScript object created using the `{}` syntax. It is a collection of key-value pairs, where each key is a string (or a symbol, in modern JavaScript) and each value can be any type of value, including strings, numbers, booleans, arrays, objects, and more. -```js +```js live const person = { name: 'John', age: 30, occupation: 'Developer' }; +console.log(person); ``` ### `Map` objects A `Map` object, introduced in ECMAScript 2015 (ES6), is a more advanced data structure that allows you to store key-value pairs with additional features. A `Map` is an iterable, which means you can use it with `for...of` loops, and it provides methods for common operations like `get`, `set`, `has`, and `delete`. -```js +```js live const person = new Map([ ['name', 'John'], ['age', 30], ['occupation', 'Developer'], ]); +console.log(person); ``` ## Key differences diff --git a/questions/what-is-the-prototype-chain-and-how-does-it-work/en-US.mdx b/questions/what-is-the-prototype-chain-and-how-does-it-work/en-US.mdx index c812362..4732fa2 100644 --- a/questions/what-is-the-prototype-chain-and-how-does-it-work/en-US.mdx +++ b/questions/what-is-the-prototype-chain-and-how-does-it-work/en-US.mdx @@ -6,7 +6,7 @@ title: What is the prototype chain and how does it work? The prototype chain is a mechanism in JavaScript that allows objects to inherit properties and methods from other objects. When you try to access a property on an object, JavaScript will first look for the property on the object itself. If it doesn't find it, it will look at the object's prototype, and then the prototype's prototype, and so on, until it either finds the property or reaches the end of the chain, which is `null`. -```js +```js live function Person(name) { this.name = name; } @@ -40,7 +40,7 @@ When you try to access a property or method on an object, JavaScript will: ### Example -```js +```js live function Person(name) { this.name = name; } @@ -64,7 +64,7 @@ In this example: JavaScript's built-in objects also use the prototype chain. For example, arrays inherit from `Array.prototype`, which in turn inherits from `Object.prototype`. -```js +```js live const arr = [1, 2, 3]; console.log(arr.toString()); // "1,2,3" ``` @@ -80,7 +80,13 @@ In this example: You can add properties and methods to an object's prototype, and all instances of that object will have access to those properties and methods. -```js +```js live +function Person(name) { + this.name = name; +} + +const alice = new Person('Alice'); + Person.prototype.sayGoodbye = function () { console.log(`Goodbye from ${this.name}`); }; diff --git a/questions/why-you-might-want-to-create-static-class-members/en-US.mdx b/questions/why-you-might-want-to-create-static-class-members/en-US.mdx index 8ea53a5..a3fa09d 100644 --- a/questions/why-you-might-want-to-create-static-class-members/en-US.mdx +++ b/questions/why-you-might-want-to-create-static-class-members/en-US.mdx @@ -6,7 +6,7 @@ title: Why might you want to create static class members in JavaScript? Static class members (properties/methods) has a `static` keyword prepended. Such members cannot be directly accessed on instances of the class. Instead, they're accessed on the class itself. -```js +```js live class Car { static noOfWheels = 4; static compare() { @@ -29,7 +29,7 @@ Static members are useful under the following scenarios: Static class members (properties/methods) are not tied to a specific instance of a class and have the same value regardless of which instance is referring to it. Static properties are typically configuration variables and static methods are usually pure utility functions which do not depend on the state of the instance. Such properties has a `static` keyword prepended. -```js +```js live class Car { static noOfWheels = 4; static compare() { @@ -43,7 +43,7 @@ console.log(Car.compare()); // Output: static method has been called. Static members are not accessible by specific instance of class. -```js +```js live class Car { static noOfWheels = 4; static compare() { @@ -58,7 +58,7 @@ console.log(car.compare()); // Error: TypeError: car.compare is not a function The `Math` class in JavaScript is a good example of a common library that uses static members. The `Math` class in JavaScript is a built-in object that provides a collection of mathematical constants and functions. It is a static class, meaning that all of its properties and methods are static. Here's an example of how the `Math` class uses static members: -```js +```js live console.log(Math.PI); // Output: 3.141592653589793 console.log(Math.abs(-5)); // Output: 5 console.log(Math.max(1, 2, 3)); // Output: 3 @@ -72,7 +72,7 @@ In this example, `Math.PI`, `Math.abs()`, and `Math.max()` are all static member Static class members can be useful for defining utility functions that don't require any instance-specific (don't use `this`) data or behavior. For example, you might have a `Arithmetic` class with static methods for common mathematical operations. -```js +```js live class Arithmetic { static add(a, b) { return a + b; @@ -90,7 +90,7 @@ console.log(Arithmetic.subtract(5, 2)); // Output: 3 Static class members can be used to implement the Singleton pattern, where you want to ensure that only one instance of a class exists throughout your application. -```js +```js live class Singleton { static instance; @@ -112,7 +112,7 @@ console.log(singleton1 === singleton2); // Output: true Static class members can be used to store configuration or settings that are shared across all instances of a class. This can be useful for things like API keys, feature flags, or other global settings. -```js +```js live class Config { static API_KEY = 'your-api-key'; static FEATURE_FLAG = true;