Skip to content

qns: address user feedback #29

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Apr 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1064,7 +1064,7 @@ The main difference lies in the bubbling behavior of `mouseenter` and `mouseover

`mouseenter` events do not bubble. The `mouseenter` event is triggered only when the mouse pointer enters the element itself, not its descendants. If a parent element has child elements, and the mouse pointer enters child elements, the `mouseenter` event will not be triggered on the parent element again, it's only triggered once upon entry of parent element without regard for its contents. If both parent and child have `mouseenter` listeners attached and the mouse pointer moves from the parent element to the child element, `mouseenter` will only fire for the child.

`mouseover` events bubble up the DOM tree. The `mouseover` event is triggered when the mouse pointer enters the element or one of its descendants. If have a parent element has child elements, and the mouse pointer enters child elements, the `mouseover` event will be triggered on the parent element again as well. If the parent element has multiple child elements, this can result in multiple event callbacks fired. If there are child elements, and the mouse pointer moves from the parent element to the child element, `mouseover` will fire for both the parent and the child.
`mouseover` events bubble up the DOM tree. The `mouseover` event is triggered when the mouse pointer enters the element or one of its descendants. If a parent element has child elements, and the mouse pointer enters child elements, the `mouseover` event will be triggered on the parent element again as well. If the parent element has multiple child elements, this can result in multiple event callbacks fired. If there are child elements, and the mouse pointer moves from the parent element to the child element, `mouseover` will fire for both the parent and the child.

| Property | `mouseenter` | `mouseover` |
| --- | --- | --- |
Expand Down Expand Up @@ -4921,7 +4921,7 @@ The main difference lies in the bubbling behavior of `mouseenter` and `mouseover

`mouseenter` events do not bubble. The `mouseenter` event is triggered only when the mouse pointer enters the element itself, not its descendants. If a parent element has child elements, and the mouse pointer enters child elements, the `mouseenter` event will not be triggered on the parent element again, it's only triggered once upon entry of parent element without regard for its contents. If both parent and child have `mouseenter` listeners attached and the mouse pointer moves from the parent element to the child element, `mouseenter` will only fire for the child.

`mouseover` events bubble up the DOM tree. The `mouseover` event is triggered when the mouse pointer enters the element or one of its descendants. If have a parent element has child elements, and the mouse pointer enters child elements, the `mouseover` event will be triggered on the parent element again as well. If the parent element has multiple child elements, this can result in multiple event callbacks fired. If there are child elements, and the mouse pointer moves from the parent element to the child element, `mouseover` will fire for both the parent and the child.
`mouseover` events bubble up the DOM tree. The `mouseover` event is triggered when the mouse pointer enters the element or one of its descendants. If a parent element has child elements, and the mouse pointer enters child elements, the `mouseover` event will be triggered on the parent element again as well. If the parent element has multiple child elements, this can result in multiple event callbacks fired. If there are child elements, and the mouse pointer moves from the parent element to the child element, `mouseover` will fire for both the parent and the child.

| Property | `mouseenter` | `mouseover` |
| --- | --- | --- |
Expand Down
2 changes: 1 addition & 1 deletion questions/describe-event-bubbling/en-US.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ child.click();

## Event delegation

Event bubbling is the basis for a technique called [event delegation](/questions/quiz/describe-event-delegation), where you attach a single event handler to a common ancestor of multiple elements and use event delegation to handle events for those elements efficiently. This is particularly useful when you have a large number of similar elements, like a list of items, and you want to avoid attaching individual event handlers to each item.
Event bubbling is the basis for a technique called [event delegation](/questions/quiz/explain-event-delegation), where you attach a single event handler to a common ancestor of multiple elements and use event delegation to handle events for those elements efficiently. This is particularly useful when you have a large number of similar elements, like a list of items, and you want to avoid attaching individual event handlers to each item.

```js
parent.addEventListener('click', (event) => {
Expand Down
2 changes: 1 addition & 1 deletion questions/explain-event-delegation/en-US.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ userForm.addEventListener('input', (event) => {
});
```

In this example, a single input event listener is attached to the form element. It can respond to input changes for all child input elements, simplifying the code by an event listeners per `<input>` element.
In this example, a single input event listener is attached to the form element. It can respond to input changes for all child input elements, simplifying the code by eliminating the need for individual listeners on each `<input>` element.

## Pitfalls

Expand Down
2 changes: 1 addition & 1 deletion questions/explain-hoisting/en-US.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,4 @@ ESLint is a static code analyzer that can find violations of such cases with the
## Further reading

- [Hoisting | MDN](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting)
- [JavaScript Visualized: Hoisting](https://dev.to/lydiahallie/javascript-visualized-hoisting-478h)
- [What is Hoisting in JavaScript?](https://www.freecodecamp.org/news/what-is-hoisting-in-javascript)
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,4 @@ fetchData((error, data) => {

- [MDN Web Docs: Callback function](https://developer.mozilla.org/en-US/docs/Glossary/Callback_function)
- [JavaScript.info: Callbacks](https://javascript.info/callbacks)
- [Node.js: Asynchronous programming and callbacks](https://nodejs.org/en/knowledge/getting-started/control-flow/what-are-callbacks/)
- [Node.js: Asynchronous programming and callbacks](https://nodejs.org/en/learn/asynchronous-work/javascript-asynchronous-programming-and-callbacks)
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ In situations where the user has navigated away from the page, aborting the requ
## Notes

- `AbortController`s is not `fetch()`-specific, it can be used to abort other asynchronous tasks as well.
- A singular `AbortContoller` instance can be reused or multiple async tasks and cancel all of them at once.
- A singular `AbortContoller` instance can be reused on multiple async tasks and cancel all of them at once.
- Calling `abort()` on `AbortController`s does not send any notification or signal to the server. The server is unaware of the cancelation and will continue processing the request until it completes or times out.

## Further reading
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,28 +58,33 @@ fetchData(); // Error fetching data: ....
If you have multiple asynchronous operations, you can nest `try...catch` blocks to handle errors at different levels.

```js live
async function fetchData() {
try {
// Invalid URl
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Error fetching data:', error);
}
async function fetchUser() {
// Simulate a successful async operation
return { id: 1, name: 'Alice' };
}

async function processData() {
async function fetchUserPosts() {
// Simulate a failed async operation
throw new Error('Failed to fetch posts');
}

async function loadUserData() {
try {
await fetchData();
// Additional processing
console.log(arr); // Trying to reference an undefined variable will throw an error
} catch (error) {
console.error('Error processing data:', error);
const user = await fetchUser();
console.log('User:', user);

try {
const posts = await fetchUserPosts();
console.log('Posts:', posts);
} catch (postsError) {
console.error('Error fetching posts:', postsError.message);
}
} catch (userError) {
console.error('Error fetching user:', userError.message);
}
}

processData();
loadUserData();
```

## Using `.catch()` with Promises
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,4 @@ In this example, the form will not submit if the `username` input is empty, and

- [MDN Web Docs: Constraint Validation](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Constraint_validation)
- [MDN Web Docs: HTMLFormElement.checkValidity()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/checkValidity)
- [MDN Web Docs: HTMLFormElement.setCustomValidity()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/setCustomValidity)
- [MDN Web Docs: HTMLObjectElement.setCustomValidity()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/setCustomValidity)
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ In JavaScript, several built-in objects implement the iterator protocol, meaning

Generators are a special kind of function that can pause and resume their execution, allowing them to generate a sequence of values on-the-fly. They are commonly used to create iterators but have other applications as well. The key use cases of generators include:

- Creating iterators is a more concise and readable way compared to manually implementing the iterator protocol.
- Creating iterators in a more concise and readable way compared to manually implementing the iterator protocol.
- Implementing lazy evaluation, where values are generated only when needed, saving memory and computation time.
- Simplifying asynchronous programming by allowing code to be written in a synchronous-looking style using `yield` and `await`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,22 @@ Layout thrashing occurs when you read and write to the DOM repeatedly, causing m

```js
// Inefficient
for (let i = 0; i < 1000; i++) {
const height = element.clientHeight;
element.style.height = `${height + 10}px`;
}
boxes.forEach((box) => {
const height = box.offsetHeight; // Read
box.style.height = `${height + 10}px`; // Write
});

// Efficient
const height = element.clientHeight;
for (let i = 0; i < 1000; i++) {
element.style.height = `${height + 10}px`;
}
// Batch read
const heights = [];
boxes.forEach((box) => {
heights.push(box.offsetHeight);
});

// Batch write
boxes.forEach((box, i) => {
box.style.height = `${heights[i] + 10}px`;
});
```

## Excessive use of global variables
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ xhr.upload.onprogress = (event) => {
The callback assigned to `onprogress` is passed a [`ProgressEvent`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/progress_event):

- The `loaded` field on the `ProgressEvent` is a 64-bit integer indicating the amount of work already performed (bytes uploaded/downloaded) by the underlying process.
- The `total` field on the `ProgressEvent` is a 64-bit integer representing the total amount of work that the underlying process is in the progress of performing. When downloading resources, this is the `Content-Length` value of the HTTP request.
- The `total` field on the `ProgressEvent` is a 64-bit integer representing the total amount of work that the underlying process is in the progress of performing. When downloading resources, this is the `Content-Length` value of the HTTP response.

On the other hand, the `fetch()` API does not offer any convenient way to track upload progress. It can be implemented by monitoring the `body` of the `Response` object as a fraction of the `Content-Length` header, but it's quite complicated.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,49 @@ function getData3() {

Promise.all([getData1(), getData2(), getData3()])
.then((results) => {
console.log(results); // Output: [[{ id: 1, title: 'Data 1' }, { id: 2, title: 'Data 2' }, { id: 3, title: 'Data 3' }]
console.log(results); // Output: [{ id: 1, title: 'Data 1' }, { id: 2, title: 'Data 2' }, { id: 3, title: 'Data 3' }]
})
.catch((error) => {
console.error('Error:', error);
});
```

### Easier error handling with `.catch()` and guaranteed cleanup with `.finally()`

Promises make error handling more straightforward by allowing you to catch errors at the end of a chain using `.catch()`, instead of manually checking for errors in every callback. This leads to cleaner and more maintainable code.

Additionally, `.finally()` lets you run code after the Promise settles, whether it was successful or failed, which is great for cleanup tasks like hiding spinners or resetting UI states.

```js live
function getFirstData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ id: 1, title: 'First Data' });
}, 1000);
});
}

function getSecondData(data) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ id: data.id, title: data.title + ' -> Second Data' });
}, 1000);
});
}

getFirstData()
.then(getSecondData)
.then((data) => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
})
.finally(() => {
console.log('This runs no matter what');
});
```

### With promises, these scenarios which are present in callbacks-only coding, will not happen:

- Call the callback too early
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function greetName(greeter, name) {
greetName(greet, 'Alice'); // Output: Hello, Alice!
```

In this example, the `greetName` function takes another function `greet` as an argument and executes it with the name `Alice`. The `greet` function is a higher-order function because it is passed as an argument to another function.
In this example, the `greetName` function is higher-order function because it takes another function (`greet`) as an argument and uses it to generate a greeting for the given name.

### Functions as return values

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ There's one final value-comparison operation within JavaScript, that is the [`Ob

## Conclusion

- Use `==` when you want to compare values with type coercion (and understand the implications of it). Practically, the only valid use case for the equality operator is when against `null` and `undefined` for convenience.
- Use `==` when you want to compare values with type coercion (and understand the implications of it). In practice, the only reasonable use case for the equality operator is to check for both `null` and `undefined` in a single comparison for convenience.
- Use `===` when you want to ensure both the value and the type are the same, which is the safer and more predictable choice in most cases.

### Notes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The main difference lies in the bubbling behavior of `mouseenter` and `mouseover

`mouseenter` events do not bubble. The `mouseenter` event is triggered only when the mouse pointer enters the element itself, not its descendants. If a parent element has child elements, and the mouse pointer enters child elements, the `mouseenter` event will not be triggered on the parent element again, it's only triggered once upon entry of parent element without regard for its contents. If both parent and child have `mouseenter` listeners attached and the mouse pointer moves from the parent element to the child element, `mouseenter` will only fire for the child.

`mouseover` events bubble up the DOM tree. The `mouseover` event is triggered when the mouse pointer enters the element or one of its descendants. If have a parent element has child elements, and the mouse pointer enters child elements, the `mouseover` event will be triggered on the parent element again as well. If the parent element has multiple child elements, this can result in multiple event callbacks fired. If there are child elements, and the mouse pointer moves from the parent element to the child element, `mouseover` will fire for both the parent and the child.
`mouseover` events bubble up the DOM tree. The `mouseover` event is triggered when the mouse pointer enters the element or one of its descendants. If a parent element has child elements, and the mouse pointer enters child elements, the `mouseover` event will be triggered on the parent element again as well. If the parent element has multiple child elements, this can result in multiple event callbacks fired. If there are child elements, and the mouse pointer moves from the parent element to the child element, `mouseover` will fire for both the parent and the child.

| Property | `mouseenter` | `mouseover` |
| --- | --- | --- |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ console.log(typeof y === 'undefined'); // true

## `undefined`

A variable that is `undefined` is a variable that has been declared, but not assigned a value. It is of type `undefined`. If a function does not return any value as the result of executing it is assigned to a variable, the variable also has the value of `undefined`. To check for it, compare using the strict equality (`===`) operator or `typeof` which will give the `'undefined'` string. Note that you should not be using the loose equality operator (`==`) to check, as it will also return `true` if the value is `null`.
A variable that is `undefined` is a variable that has been declared, but not assigned a value. It is of type `undefined`. If a function does not return a value, and its result is assigned to a variable, that variable will also have the value `undefined`. To check for it, compare using the strict equality (`===`) operator or `typeof` which will give the `'undefined'` string. Note that you should not be using the loose equality operator (`==`) to check, as it will also return `true` if the value is `null`.

```js live
let foo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const person1 = { name: 'John' };
const person2 = { name: 'Alice' };

greet.call(person1); // Hello, my name is John
greet.call(person2); // Hello, my name is Alice
greet.apply(person2); // Hello, my name is Alice
```

### Alternative syntax to call methods on objects
Expand Down