1/88
Looks like no tags are added yet.
Name | Mastery | Learn | Test | Matching | Spaced |
---|
No study sessions yet.
Explain your understanding of the box model and how you would tell the browser in CSS to render your layout in different box models.
The box model are rectangular boxes around elements. Each box contains content along with padding, border, and margin.
box-sizing is used to render in different box models.
content-box: default
border-box: removes margin from calculation
What does * { box-sizing: border-box; }
do?
Changes how elements width and height are calculated: now includes padding and border.
What is CSS selector specificity and how does it work?
The order of which CSS is applied.
inline style
number of ID selectors
number of classes, attributes and pseudo-classes selectors
number of tags and pseudo-elements selectors
What is the CSS display
property and can you give a few examples of its use?
Changes the display of an element(s)
none
block
inline
inline-block
flex
grid
What's the difference between a relative
, fixed
, absolute
, sticky
and static
-ally positioned element?
static - default where position of element will flow normally and the top
, right
, bottom
, left
and z-index
properties do not apply
relative - positioned relative to its normal position
absolute - does not follow normal flow and and positioned along its closest ancestor
fixed - removed from the flow of the page and positioned at a specified position relative to the viewport and doesn't move when scrolled
sticky - hybrid of relative and fixed positioning. The element is treated as relative positioned until it crosses a specified threshold, at which point it is treated as fixed-positioned
What's the difference between inline
and inline-block
?
block | inline-block | inline | |
Size | Fills up the width of its parent container. | Depends on content. | Depends on content. |
Positioning | Start on a new line and tolerates no HTML elements next to it (except when you add | Flows along with other content and allows other elements beside it. | Flows along with other content and allows other elements beside it. |
Can specify | Yes | Yes | No |
Can be aligned with | No | Yes | Yes |
Margins and paddings | All sides respected. | All sides respected. | Only horizontal sides respected. Vertical sides, if specified, do not affect layout. Vertical space it takes up depends on |
Float | Becomes like a |
Explain the concept of "hoisting" in JavaScript
Variable declarations (var
): Declarations are hoisted, but not initializations. The value of the variable is undefined
if accessed before initialization.
Variable declarations (let
and const
): Declarations are hoisted, but not initialized. Accessing them results in ReferenceError
until the actual declaration is encountered.
Function expressions (var
): Declarations are hoisted, but not initializations. The value of the variable is undefined
if accessed before initialization.
Function declarations (function
): Both declaration and definition are fully hoisted.
Class declarations (class
): Declarations are hoisted, but not initialized. Accessing them results in ReferenceError
until the actual declaration is encountered.
Import declarations (import
): Declarations are hoisted, and side effects of importing the module are executed before the rest of the code.
What is React? Describe the benefits of React
JavaScript library for building single-page apps. It’s based on reusable components with their own states.
Benefits
modular code
more readable code
one-way data binding for predictable data flow
virtual DOM for efficient updates
What are the differences between JavaScript variables created using let
, var
or const
?
Differ in scope, initialization rules, whether they can be redeclared or reassigned and the behavior when they are accessed before declaration.
What is the difference between ==
and ===
in JavaScript?
The ==
operator will compare for equality after doing any necessary type conversions. The ===
operator will not do type conversion.
What is the event loop in JavaScript runtimes?
The event loop deals with how async operations are executed within the browser runtime environment.
Executes scripts and puts sync operations on the stack
Async operations are off loaded to Web API or Node.js API
When async operations finish, it’s callbacks are placed in either macrotask queue or microtask queue
Event loop finishes the stack
Micro queue is processed and pushed onto stack
Macro queue (web APIs) is processed and pushed onto stack
cycles back to micro queue
What is the difference between state and props in React?
State is used for data that changes within a component, whereas props are used to pass data and event handlers to child components.
Explain event delegation in JavaScript
Event listener on parent and events that occur in children are bubbled up to parent where it is then handled
What is the purpose of the key
prop in React?
Used to uniquely identify elements in a list. It helps React optimize rendering by efficiently updating and reordering elements.
Explain how this
works in JavaScript
If the new
keyword is used when calling the function, meaning the function was used as a function constructor, the this
inside the function is the newly-created object instance.
If this
is used in a class
constructor
, the this
inside the constructor
is the newly-created object instance.
If apply()
, call()
, or bind()
is used to call/create a function, this
inside the function is the object that is passed in as the argument.
If a function is called as a method (e.g. obj.method()
) — this
is the object that the function is a property of.
If a function is invoked as a free function invocation, meaning it was invoked without any of the conditions present above, this
is the global object. In the browser, the global object is the window
object. If in strict mode ('use strict';
), this
will be undefined
instead of the global object.
If multiple of the above rules apply, the rule that is higher wins and will set the this
value.
If the function is an ES2015 arrow function, it ignores all the rules above and receives the this
value of its surrounding scope at the time it is created.
Describe the difference between a cookie, sessionStorage
and localStorage
in browsers
Cookies: Suitable for server-client communication, small storage capacity, can be persistent or session-based, domain-specific. Sent to the server on every request.
localStorage
: Suitable for long-term storage, data persists even after the browser is closed, accessible across all tabs and windows of the same origin, highest storage capacity among the three.
sessionStorage
: Suitable for temporary data within a single page session, data is cleared when the tab or window is closed, has a higher storage capacity compared to cookies.
Describe the difference between <script>
, <script async>
and <script defer>
All of these ways (<script>
, <script async>
, and <script defer>
) are used to load and execute JavaScript files in an HTML document, but they differ in how the browser handles loading and execution of the script:
<script>
is the default way of including JavaScript. The browser blocks HTML parsing while the script is being downloaded and executed. The browser will not continue rendering the page until the script has finished executing.
<script async>
downloads the script asynchronously, in parallel with parsing the HTML. Executes the script as soon as it is available, potentially interrupting the HTML parsing. <script async>
do not wait for each other and execute in no particular order.
<script defer>
downloads the script asynchronously, in parallel with parsing the HTML. However, the execution of the script is deferred until HTML parsing is complete, in the order they appear in the HTML.
What's the difference between a JavaScript variable that is: null
, undefined
or undeclared?
Trai | null | undefined | Undeclared |
Meaning | Explicitly set by the developer to indicate that a variable has no value | Variable has been declared but not assigned a value | Variable has not been declared at all |
Type |
|
| Throws a |
Equality Comparison |
|
| Throws a |
What are the benefits of using hooks in React?
They make it easier to reuse stateful logic between components, improve code readability.
What's the difference between .call
and .apply
in JavaScript?
.call
and .apply
are both used to invoke functions with a specific this
context and arguments. The primary difference lies in how they accept arguments:
.call(thisArg, arg1, arg2, ...)
: Takes arguments individually.
.apply(thisArg, [argsArray])
: Takes arguments as an array.
Why is it generally a good idea to position CSS <link>
s between <head></head>
and JS <script>
s just before </body>
?
Allows for faster rendering of the page and better overall performance.
Explain how a browser determines what elements match a CSS selector.
Browsers match selectors from rightmost (key selector) to the left. Browsers filter out elements in the DOM according to the key selector and traverse up its parent elements to determine matches. The shorter the length of the selector chain, the faster the browser can determine if that element matches the selector.
Have you played around with the new CSS Flexbox or Grid specs?
Flexbox is mainly meant for 1-dimensional layouts while Grid is meant for 2-dimensional layouts.
Is there any reason you'd want to use translate()
instead of absolute
positioning, or vice-versa? And why?
translate()
is more efficient and will result in shorter paint times for smoother animations.
What are the rules of React hooks?
Always call hooks at the top level of your React function, never inside loops, conditions, or nested functions. Only call hooks from React function components or custom hooks.
Explain Function.prototype.bind
in JavaScript
Function.prototype.bind
is a method in JavaScript that allows you to create a new function with a specific this
value and optional initial arguments. It's primary purpose is to:
Binding this
value to preserve context: The primary purpose of bind
is to bind the this
value of a function to a specific object. When you call func.bind(thisArg)
, it creates a new function with the same body as func
, but with this
permanently bound to thisArg
.
Partial application of arguments: bind
also allows you to pre-specify arguments for the new function. Any arguments passed to bind
after thisArg
will be prepended to the arguments list when the new function is called.
Method borrowing: 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.
What advantage is there for using the JavaScript arrow syntax for a method in a constructor?
The value of this
gets set at the time of the function creation and can't change after that. When the constructor is used to create a new object, this
will always refer to that object.
Explain how prototypal inheritance works in JavaScript
Every JavaScript object has a special hidden property called [[Prototype]]
When a property is accessed on an object and if the property is not found on that object, the JavaScript engine looks at the object's __proto__...
Difference between: function Person(){}
, const person = Person()
, and const person = new Person()
in JavaScript?
function Person(){}
: A function declaration in JavaScript. It can be used as a regular function or as a constructor.
const person = Person()
: Calls Person
as a regular function, not a constructor. If Person
is intended to be a constructor, this will lead to unexpected behavior.
const person = new Person()
: Creates a new instance of Person
, correctly utilizing the constructor function to initialize the new object.
Explain the differences on the usage of foo
between function foo() {}
and var foo = function() {}
in JavaScript
function foo() {}
a function declaration while the var foo = function() {}
is a function expression. The key difference is that function declarations have its body hoisted but the bodies of function expressions are not (they have the same hoisting behavior as var
-declared variables).
If you try to invoke a function expression before it is declared, you will get an Uncaught TypeError: XXX is not a function
error.
Function declarations can be called in the enclosing scope even before they are declared.
What's a typical use case for anonymous functions in JavaScript?
Anonymous function in Javascript is a function that does not have any name associated with it. They are typically used as arguments to other functions or assigned to variables.
What are the various ways to create objects in JavaScript?
Object literals ({}
): Simplest and most popular approach. Define key-value pairs within curly braces.
Object()
constructor: Use new Object()
with dot notation to add properties.
Object.create()
: Create new objects using existing objects as prototypes, inheriting properties and methods.
Constructor functions: Define blueprints for objects using functions, creating instances with new
.
ES2015 classes: Structured syntax similar to other languages, using class
and constructor
keywords.
What is a closure in JavaScript, and how/why would you use one?
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.
What is the definition of a higher-order function in JavaScript?
A higher-order function is any function that takes one or more functions as arguments, which it uses to operate on some data, and/or returns a function as a result.
Array.prototype.map() etc.
What does re-rendering mean in React?
Re-rendering in React refers to the process where a component updates its output to the DOM in response to changes in state or props. When a component's state or props change, React triggers a re-render to ensure the UI reflects the latest data. This process involves calling the component's render method again to produce a new virtual DOM, which is then compared to the previous virtual DOM to determine the minimal set of changes needed to update the actual DOM.
What are the differences between JavaScript ES2015 classes and ES5 function constructors?z
Feature | ES5 Function | ConstructorES2015 Class |
Syntax | Uses function constructors and prototypes | Uses |
Constructor | Function with properties assigned using |
|
Method Definition | Defined on the prototype | Defined inside the class body |
Static Methods | Added directly to the constructor function | Defined using the |
Inheritance | Uses | Uses |
Readability | Less intuitive and more verbose | More concise and intuitive |
Describe event bubbling in JavaScript and browsers
Event bubbling is a DOM event propagation mechanism where an event (e.g. a click), starts at the target element and bubbles up to the root of the document. This allows ancestor elements to also respond to the event.
Event bubbling is essential for event delegation, where a single event handler manages events for multiple child elements, enhancing performance and code simplicity. While convenient, failing to manage event propagation properly can lead to unintended behavior, such as multiple handlers firing for a single event.
Describe event capturing in JavaScript and browsers
Event capturing is a lesser-used counterpart to event bubbling in the DOM event propagation mechanism. It follows the opposite order, where an event triggers first on the ancestor element and then travels down to the target element.
Explain the difference between synchronous and asynchronous functions in JavaScript
Synchronous functions execute in a sequential order, one after the other. Each operation must wait for the previous one to complete before moving on to the next.
Synchronous code is blocking, meaning the program execution halts until the current operation finishes.
It follows a strict sequence, executing instructions line by line.
Synchronous functions are easier to understand and debug since the flow is predictable.
Asynchronous functions do not block the execution of the program. They allow other operations to continue while waiting for a response or completion of a time-consuming task.
Asynchronous code is non-blocking, allowing the program to keep running without waiting for a specific operation to finish.
It enables concurrent execution, improving performance and responsiveness.
Asynchronous functions are commonly used for tasks like network requests, file I/O, and timers.
What are the pros and cons of using Promises instead of callbacks in JavaScript?
Promises offer a cleaner alternative to callbacks, helping to avoid callback hell and making asynchronous code more readable. They facilitate writing sequential and parallel asynchronous operations with ease. However, using promises may introduce slightly more complex code.
How would one optimize the performance of React contexts to reduce rerenders?
To optimize the performance of React contexts and reduce rerenders, you can use techniques such as memoizing context values, splitting contexts, and using selectors. Memoizing context values with useMemo
ensures that the context value only changes when its dependencies change. Splitting contexts allows you to isolate state changes to specific parts of your application. Using selectors with libraries like use-context-selector
can help you only rerender components that actually need the updated context value.
How do you handle asynchronous data loading in React applications?
In React applications, asynchronous data loading is typically handled using useEffect
and useState
hooks. You initiate the data fetch inside useEffect
and update the state with the fetched data. This ensures that the component re-renders with the new data.
How do you decide between using React state, context, and external state managers?
Choosing between React state, context, and external state managers depends on the complexity and scope of your application's state management needs. Use React state for local component state, React context for global state that needs to be shared across multiple components, and external state managers like Redux or MobX for complex state management that requires advanced features like middleware, time-travel debugging, or when the state needs to be shared across a large application.
What is virtual DOM in React?
The virtual DOM in React is a lightweight copy of the actual DOM. It allows React to efficiently update the UI by comparing the virtual DOM with the real DOM and only making necessary changes. This process is called reconciliation. By using the virtual DOM, React minimizes direct manipulation of the real DOM, which can be slow and inefficient.
How does virtual DOM in React work? What are its benefits and downsides?
The virtual DOM in React is a lightweight copy of the actual DOM. When the state of a component changes, React creates a new virtual DOM tree and compares it with the previous one using a process called "reconciliation." Only the differences are then updated in the actual DOM, making updates more efficient. The benefits include improved performance and a more declarative way to manage UI. However, it can add complexity and may not be as performant for very simple applications.
What is reconciliation in React?
Reconciliation in React is the process through which React updates the DOM to match the virtual DOM. When a component's state or props change, React creates a new virtual DOM tree and compares it with the previous one. This comparison process is called "diffing." React then updates only the parts of the actual DOM that have changed, making the updates efficient and fast.
What is the difference between React Node, React Element, and a React Component?
A React Node is any renderable unit in React, such as an element, string, number, or null
. A React Element is an immutable object describing what to render, created using JSX or React.createElement
. A React Component is a function or class that returns React Elements, enabling the creation of reusable UI pieces.
What is JSX and how does it work?
JSX stands for JavaScript XML. It is a syntax extension for JavaScript that allows you to write HTML-like code within JavaScript. JSX makes it easier to create React components by allowing you to write what looks like HTML directly in your JavaScript code. Under the hood, JSX is transformed into JavaScript function calls, typically using a tool like Babel. For example, <div>Hello, world!</div>
in JSX is transformed into React.createElement('div', null, 'Hello, world!')
.
What is the consequence of using array indices as the value for key
s in React?
Using array indices as the value for key
s in React can lead to performance issues and bugs. When the order of items changes, React may not correctly identify which items have changed, leading to unnecessary re-renders or incorrect component updates. It's better to use unique identifiers for key
s to ensure React can efficiently manage and update the DOM.
What are some pitfalls about using context in React?
Using context in React can lead to performance issues if not managed properly. It can cause unnecessary re-renders of components that consume the context, even if the part of the context they use hasn't changed. Additionally, overusing context for state management can make the code harder to understand and maintain. It's important to use context sparingly and consider other state management solutions
Describe Block Formatting Context (BFC) and how it works.
A Block Formatting Context (BFC) is part of the visual CSS rendering of a web page in which block boxes are laid out. Floats, absolutely positioned elements, inline-blocks
, table-cells
, table-caption
s, and elements with overflow
other than visible
(except when that value has been propagated to the viewport) establish new block formatting contexts.
Knowing how to establish a block formatting context is important, because without doing so, the containing box will not contain floated children. This is similar to collapsing margins, but more insidious as you will find entire boxes collapsing in odd ways.
A BFC is an HTML box that satisfies at least one of the following conditions:
The value of float
is not none
.
The value of position
is neither static
nor relative
.
The value of display
is table-cell
, table-caption
, inline-block
, flex
, or inline-flex
, grid
, or inline-grid
.
The value of overflow
is not visible
.
In a BFC, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch).
Describe float
s and how they work.
Float is a CSS positioning property. Floated elements remain a part of the flow of the page, and will affect the positioning of other elements (e.g. text will flow around floated elements)
Describe pseudo-elements and discuss what they are used for.
A CSS pseudo-element is a keyword added to a selector that lets you style a specific part of the selected element(s). They can be used for decoration (::first-line
, ::first-letter
)
Describe z-index
and how stacking context is formed.
z-index: Controls the vertical stacking order of positioned elements (non-static). Higher z-index appears on top.
Default Stacking: Elements stack in DOM order (later elements on top), with positioned elements always above static ones.
Stacking Context: A "mini stacking world" created by certain CSS properties (e.g., opacity < 1, filter, transform).
How it works:
z-index inside a stacking context is relative to its parent, not the whole document.
Elements outside a context can't be interleaved with elements inside.
Stacking contexts are self-contained; once stacked internally, they are treated as a single unit in the parent context.
What kind of things must you be wary of when designing or developing for multilingual sites?
SEO:
lang attribute in <html>
Locale in URL
<link rel="alternate" hreflang="..."> for other locales, x-default fallback
Locale vs. Language:
Locale: Number/date/time formatting.
Language: Varies by country (grammar, spelling, etc.). Be specific (e.g., en-US, en-GB, not just en).
Don't Assume:
Predict locale from headers/IP, but allow easy switching.
Text Length:
Varies by language (e.g., German longer than English).
Design for flexible layouts; avoid fixed-width elements or character-count dependencies.
Reading Direction:
Some languages are right-to-left (e.g., Arabic, Hebrew).
Design must accommodate layout and element placement changes.
String Concatenation:
Don't concatenate translated strings ("The date is " + date).
Use template strings with parameters to handle different word orders.
Explain CSS sprites, and how you would implement them on a page or site.
What: Combine multiple images (usually icons) into a single image file (a "sprite sheet").
Why (Historically): Reduce HTTP requests. Fewer requests meant faster page loads (less important with HTTP/2).
How:
Create Sprite Sheet: Use a tool (e.g., a sprite generator) to combine images.
CSS:
background-image: Points to the sprite sheet.
background-position: Specifies X and Y coordinates to select the desired image portion.
width and height: Define the dimensions of the individual icon.
HTML: Apply classes to elements to display specific icons.
Pros: Reduced HTTP requests (less relevant now), preloading of images.
Cons: Can be complex to manage, not as flexible as individual images, accessibility can be affected if not used with proper implementation.
Have you ever used a grid system, and if so, what do you prefer?
Yes, I use it for grid-like layouts compared to flex box for flexible layouts.
How do you serve a page with content in multiple languages?
Key Idea: The goal is to detect the user's preferred language, serve the appropriate content, and inform search engines about the different language versions of the page.
Detect User's Language:
Accept-Language Header: Browser sends preferred languages.
IP Geolocation: Infer location (less reliable).
User Selection: Allow users to choose their language.
Serve Correct Content:
Server-Side Rendering:
Placeholders in HTML.
Server replaces placeholders with translated strings (from database, files, or translation service).
Client-Side Rendering:
JavaScript fetches translated strings (e.g., JSON files).
Client-side framework (e.g., React, Vue, Angular) renders content.
Inform Search Engines:
<html> lang Attribute: <html lang="es"> for Spanish.
<link rel="alternate" hreflang="xx">:
Indicates alternate versions of the page for different languages.
Example: <link rel="alternate" hreflang="de" href="http://de.example.com/page.html" />
Use x-default for a fallback page.
URL Structure:
Language Codes in URL
* /en/page
* /de/page
* en.example.com
* example.com/de
Country Codes in URL (if targeting specific regions):
* /en-us/page
* /en-gb/page
* example.com/en-CA/page
How do you serve your pages for feature-constrained browsers?
Graceful degradation: The practice of building an application for modern browsers while ensuring it remains functional in older browsers.
Progressive enhancement: The practice of building an application for a base level of user experience, but adding functional enhancements when a browser supports it.
Use caniuse.com to check for feature support.
Autoprefixer for automatic vendor prefix insertion.
Feature detection using Modernizr.
Use CSS Feature queries via @support
`
How is responsive design different from adaptive design?
Responsive: One-size-fits-all, fluidly adjusting to the screen.
Adaptive: Tailored experiences based on detected device/screen size.
Responsive is generally more recommended in modern development due to maintainability
Responsive: A single, stretchy rubber band that fits around different objects.
Adaptive: A set of different-sized rubber bands, each designed for a specific object.
Feature | Responsive Design | Adaptive Design |
Principle | Flexibility | Progressive Enhancement |
Layout | Single, fluid layout | Multiple, fixed layouts |
Approach | Adapts to any screen size | Predefined layouts for specific screen sizes/devices |
Techniques | Media queries, flexible grids, responsive images | Device/feature detection, separate layouts |
Analogy | One ball that changes size | Different balls for different hoop sizes |
Challenges | Can be complex, breakpoint decisions | Requires device detection (can be unreliable), more layouts to maintain. |
How would you approach fixing browser-specific styling issues?
After identifying the issue and the offending browser, use a separate style sheet that only loads when that specific browser is being used. This technique requires server-side rendering though.
Use libraries like Bootstrap that already handles these styling issues for you.
Use autoprefixer
to automatically add vendor prefixes to your code.
Use Reset CSS or Normalize.css.
If you're using PostCSS (or a similar CSS transpilation library), there may be plugins which allow you to opt in to using modern CSS syntax (and even W3C proposals) that will transform those sections of your code into equivalent backward-compatible code that will work in the targets you've used.
What are data-
attributes good for?
Historically: Stored extra data directly in DOM when no appropriate attribute or element existed.
Third-party Libraries: Used by libraries like Bootstrap to connect elements and add functionality (e.g., triggering modals).
Generally Discouraged Now:
Security: Easily modified by users in the browser.
Better Practices: Store data in JavaScript and sync with DOM using techniques like virtual DOM or data binding.
Valid Use Case: End-to-End Testing:
Add unique identifiers (e.g., data-test-id) for testing frameworks.
Avoids adding classes/IDs solely for testing, keeping markup clean.
In Essence: They were good for adding custom data to elements before modern practices, but are now mostly useful for testing element identification.
What are the advantages/disadvantages of using CSS preprocessors?
Advantages:
Maintainability: CSS structure is more organized and easier to maintain.
Nested Selectors: Simplifies writing complex, nested selectors.
Theming: Variables allow for consistent theming and easy theme sharing across projects.
Code Reusability: Mixins enable generation of repeated CSS patterns.
Configuration: Features like loops, lists, and maps (in Sass/Less) can simplify configurations.
File Splitting: Allows splitting code into multiple files for better organization during development, without the extra HTTP requests of splitting regular CSS.
Disadvantages:
Preprocessing Required: Needs additional tools for compiling to regular CSS.
Compilation Time: Re-compilation can be slow, especially for large projects.
Not Future-Proof: Writing code that isn't directly usable CSS.
Contrast with tools like postcss-loader which allow writing future-compatible CSS (e.g., using CSS variables).
Using preprocessor-specific features might not be valuable if they become standardized in CSS directly.
Learning Curve: Requires learning the specific syntax of the preprocessor.
What are the different ways to visually hide content (and make it available only for screen readers)?
Techniques:
Small/Zero Size:
width: 1px; height: 1px; + clip to minimize element's visual space.
Avoid width: 0; height: 0; as search engines might penalize it.
Absolute Positioning:
position: absolute; left: -99999px; to move element off-screen.
Caution: Not suitable for focusable elements (links, form controls) as they can still be tabbed to by keyboard users, causing confusion. Use this only when your contents contain only text.
Text Indentation:
text-indent: -9999px; (only works for text within block elements).
Same caution as absolute positioning for focusable elements.
Incorrect Techniques (hide from screen readers too):
display: none;
visibility: hidden;
HTML hidden attribute
Recommended Practice:
Combine multiple techniques for cross-browser compatibility.
Best: Use established CSS frameworks' solutions (battle-tested):
Tailwind CSS: .sr-only class
Bootstrap: .visually-hidden, .visually-hidden-focusable classes
In essence: These techniques hide the content from sighted users by making it extremely small or positioned off-screen while ensuring screen readers can still access it. Avoid methods that completely remove the content from the accessibility tree.
What is progressive rendering?
Definition: Techniques to improve perceived web page load time by rendering content for display as quickly as possible.
Relevance:
Historically important with slow internet connections.
Still relevant for mobile data and unreliable connections.
Key Techniques:
Lazy Loading of Images:
Defer loading images until they are about to scroll into view.
Methods:
loading="lazy" attribute (modern browsers)
JavaScript to monitor scroll position and load images dynamically
Prioritizing Visible Content (Above-the-Fold Rendering):
Load only essential CSS/content/scripts for the initially visible portion of the page.
Defer or load other resources later using events like DOMContentLoaded or load.
Async HTML Fragments:
Send parts of the HTML to the browser as they are ready on the server-side (not waiting for the entire page to be generated).
Goal: Display something to the user as quickly as possible, then progressively load the rest, improving the user experience.
In essence: Load what the user can immediately see first and the load the other resources as the user scrolls down the page or as resources become available.
What's the difference between feature detection, feature inference, and using the UA string?
1. Feature Detection:
Definition: Directly checks if a browser supports a specific feature.
Example:
if ('geolocation' in navigator) {
// Use geolocation
} else {
// Handle absence
}
content_copydownload
Use code with caution.JavaScript
Pros: Most reliable and accurate.
Cons: Can be verbose if checking many features.
Recommendation: Use this method. Consider a library like Modernizr.
2. Feature Inference:
Definition: Checks for one feature and assumes another related feature also exists.
Example:
if (document.getElementsByTagName) {
element = document.getElementById(id); // Assumes getElementById exists
}
content_copydownload
Use code with caution.JavaScript
Pros: Simpler code than full feature detection.
Cons: Less reliable; assumptions might be wrong.
Recommendation: Avoid. Feature detection is preferred.
3. UA String (User-Agent String):
Definition: A string sent by the browser that identifies its application type, OS, vendor, and version. Accessed via navigator.userAgent.
Pros: Can potentially identify specific browser versions.
Cons:
Difficult to parse accurately.
Easily spoofed (faked).
Unreliable: Browsers may misreport themselves (e.g., Chrome reporting as Safari).
Recommendation: Avoid. Unreliable and not future-proof.
Summary:
Feature Detection: Best approach. Directly test for what you need.
Feature Inference: Risky; don't rely on assumptions.
UA String: Unreliable and should be avoided.
In essence: Always check for the features you intend to use directly instead of trying to identify the browser type or make assumptions about one feature implying another.
What's the difference between "resetting" and "normalizing" CSS?
Term | Definition |
Resetting | Resetting is meant to strip all default browser styling on elements. For e.g. |
Normalizing | Normalizing preserves useful default styles rather than "unstyling" everything. It also corrects bugs for common browser dependencies. |
Choose resetting when you need to have a very customized or unconventional site design such that you need to do a lot of your own styling and do not need any default styling to be preserved.
Why you would use a srcset
attribute in an image tag?
Purpose: Serve different images based on device display width and resolution.
High-resolution displays (Retina): Higher quality images for a sharper experience.
Low-resolution/narrow screens: Lower quality images for better performance and reduced data usage.
Example:
<img srcset="small.jpg 500w, medium.jpg 1000w, large.jpg 2000w" src="fallback.jpg" alt="">
content_copydownload
Use code with caution.Html
srcset Syntax:
image-name.jpg: The filename of the image.
500w: The image's intrinsic width in pixels (not display width).
Browser Evaluation Process (example with device width 320px):
Calculate Ratios: Divide each image width (w) by the device width.
small.jpg (500w): 500 / 320 = 1.5625
medium.jpg (1000w): 1000 / 320 = 3.125
large.jpg (2000w): 2000 / 320 = 6.25
1x Display: Choose the image with the ratio closest to 1.
Retina (2x) Display:
Choose the image with the ratio closest to 2, but not less than 2, then the image closest to 2.
Avoids blurry images by not selecting a ratio that's too low.
Choose src if srcset not supported: Browsers that don't understand srcset use the src attribute as a fallback.
Benefits:
Performance: Smaller images for smaller screens mean faster loading.
User Experience: Sharper images on high-resolution displays.
Data Savings: Avoids sending unnecessarily large images to devices that don't need them.
In essence: srcset lets you tell the browser about different image sources and their widths, and the browser intelligently picks the most appropriate one based on the device's screen size and resolution.
What does the dependency array of useEffect
affect?
useEffect in a Nutshell:
Handles side effects in functional components (data fetching, subscriptions, DOM manipulation).
Takes two arguments:
A function containing the side effect logic.
An optional dependency array.
Dependency Array's Role: Determines when the effect function re-runs.
How it Affects useEffect:
[] (Empty Array):
Effect runs once after the initial render.
Like componentDidMount in class components.
[dep1, dep2, ...] (Array with Variables):
Effect runs after initial render and whenever any of the specified dependencies change.
React does a shallow comparison to check for changes.
No Dependency Array (Omitted):
Effect runs after every render.
Can cause performance issues.
Common Pitfalls:
Stale Closures:
If effect uses state/props without them in the dependency array, it might use outdated values.
Solution: Include all state/props the effect depends on in the array.
Example: Add count to the dependency array: useEffect(() => { ... }, [count]);
Functions as Dependencies:
Functions are recreated on each render, causing unnecessary effect re-runs if in the dependency array.
Solution: Use useCallback to memoize functions used in the dependency array.
Example: const handleClick = useCallback(() => { ... }, []);
In essence: The dependency array tells React which variables to "watch". If those variables change between renders, React re-runs the effect. If the array is empty, the effect runs only once. If the array is omitted, the effect runs every time. Use the dependency array to control when an effect should happen and prevent unexpected bugs or performance issues.
What is the useRef
hook in React and when should it be used?
useRef in a Nutshell:
Creates a mutable object that persists across renders.
The object has a .current property, initialized with the value passed to useRef(initialValue).
Key: Updating .current does not cause a re-render.
Use Cases:
Accessing and Manipulating DOM Elements:
Directly interact with DOM nodes (e.g., focusing an input, getting element dimensions).
Useful when React's declarative model isn't sufficient.
Example:
const inputRef = useRef(null);
useEffect(() => { inputRef.current.focus(); }, []);
// inputRef.current is the <input> element
content_copydownload
Use code with caution.JavaScript
Storing Mutable Values without Re-renders:
Keep track of values that change over time but shouldn't trigger re-renders (e.g., counters, timers, flags).
Example:
const count = useRef(0);
const increment = () => { count.current++; };
// count.current changes, but the component doesn't re-render
content_copydownload
Use code with caution.JavaScript
Keeping a Reference to a Previous Value:
Store a value from a previous render without causing a re-render when it changes.
Useful for comparing previous and current state or props.
Example:
const prevCountRef = useRef();
useEffect(() => { prevCountRef.current = count; }, [count]);
// prevCountRef.current holds the previous count value
content_copydownload
Use code with caution.JavaScript
Key Differences from useState:
useState: Updates trigger re-renders. Use for values that affect the UI.
useRef: Updates do not trigger re-renders. Use for values that don't directly affect the UI or for DOM manipulation.
In essence: useRef provides a way to "escape" React's render cycle. It's for mutable data that either needs to directly interact with the DOM or needs to persist across renders without causing updates to the UI. Use it wisely, as it can make your component's behavior less predictable if overused.
What is the useCallback
hook in React and when should it be used?
In essence: useCallback is a performance optimization tool. It's most effective when passing callbacks to child components that are optimized to prevent re-renders based on prop changes. Use it when you have a function passed as a prop and you want to ensure its reference stability to optimize rendering behavior. Be mindful of the dependency array and avoid overusing it.
useCallback in a Nutshell:
Memoizes a callback function.
Returns the same function instance between renders unless its dependencies change.
Syntax:
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]); // Dependency array
content_copydownload
Use code with caution.JavaScript
Purpose: Optimize performance by preventing unnecessary recreation of functions.
Primary Use Case:
Passing callbacks to optimized child components:
Child components using React.memo (or shouldComponentUpdate) rely on reference equality of props to avoid re-renders.
Without useCallback, a new function is created on each parent render, causing the child to re-render even if the function's logic hasn't changed.
useCallback ensures the same function instance is passed as long as dependencies are the same.
Example:
const ParentComponent = () => {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
setCount(count + 1);
}, [count]); // handleClick is stable unless count changes
return <ChildComponent onClick={handleClick} />;
};
const ChildComponent = React.memo(({ onClick }) => {
console.log('ChildComponent rendered'); // Only renders when onClick reference changes
return <button onClick={onClick}>Click me</button>;
});
content_copydownload
Use code with caution.JavaScript
Benefits:
Performance: Reduces unnecessary re-renders of child components.
Efficiency: Avoids the overhead of recreating functions on every render.
Caveats:
Overuse: Can make code more complex. Use only when necessary for performance.
Dependencies: Must include all variables used inside the callback in the dependency array to prevent stale closures.
What is the useMemo
hook in React and when should it be used?
In essence: useMemo optimizes performance by caching the result of expensive calculations. It only recomputes the value when its dependencies change, preventing redundant work.
What is useMemo?
A React hook that memoizes (caches) the result of a function call.
Returns the cached value unless one of its dependencies has changed.
Syntax:
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
// ^ ^ ^
// memoized result function to compute value dependency array
content_copydownload
Use code with caution.JavaScript
When to Use It:
Expensive Calculations:
When a function performs a computationally heavy operation that you don't want to repeat on every render.
Example:
const memoizedValue = useMemo(() => expensiveCalculation(number), [number]);
// expensiveCalculation only runs when 'number' changes
content_copydownload
Use code with caution.JavaScript
Avoiding Unnecessary Child Re-renders:
When a child component relies on a complex or derived value, useMemo can prevent the child from re-rendering if the computed value hasn't changed.
Example:
const sortedItems = useMemo(() => items.sort((a, b) => a - b), [items]);
// sortedItems is only recomputed when 'items' changes
content_copydownload
Use code with caution.JavaScript
Caveats:
Overuse: Can make code harder to read without significant gains if used for trivial calculations. Use it sparingly.
Dependencies:
Crucial: Specify all variables used in the function within the dependency array.
Missing dependencies: Lead to stale (outdated) cached values.
Extra dependencies: Cause unnecessary recalculations.
Key Difference from useCallback:
useMemo: Memoizes the result of a function call (a value).
useCallback: Memoizes the function itself (a callback).
Use useMemo for values, useCallback for functions.
What is the useReducer
hook in React and when should it be used?
In essence: useReducer is for managing complex state in React, especially when the new state depends on the previous state or when you have multiple values to update together. It's like a mini version of Redux inside your component.
Introduction:
An alternative to useState for managing state in functional components.
Best suited for complex state scenarios.
Inspired by the reduce function in JavaScript arrays.
Syntax:
const [state, dispatch] = useReducer(reducer, initialState);
// ^ ^ ^ ^
// current function reducer initial
// state to update function state value
// state
content_copydownload
Use code with caution.JavaScript
Reducer Function:
A pure function that takes the current state and an action object.
Returns the new state based on the action.
Example:
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
content_copydownload
Use code with caution.JavaScript
dispatch Function:
Used to trigger state updates.
You pass an action object to dispatch.
The reducer function then uses this action to calculate the new state.
Example Usage:
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
}
content_copydownload
Use code with caution.JavaScript
When to Use useReducer:
Complex State: When the state has multiple sub-values or is nested.
Dependent State: When the next state depends on the previous state.
Predictable State Management: When you want a more structured way to manage state transitions (similar to Redux).
Performance Optimization: In some cases, it can help optimize performance by preventing unnecessary re-renders when updating complex state.
useReducer vs. useState:
useState: Simpler for basic state management.
useReducer: Better for complex state, dependent state, and more predictable state updates.
What are React Fragments used for?
In essence: React Fragments let you group multiple elements in a component's render output without adding an extra wrapping element to the actual DOM. They keep your DOM cleaner and can improve performance.
Purpose: Group elements without adding extra nodes to the DOM.
Why They're Useful:
Avoid Unnecessary Wrapper Elements: Keeps the rendered HTML cleaner and more semantic.
Performance: Reduces DOM size, potentially improving rendering speed, especially in large lists or complex UIs.
When to Use Them:
Returning Multiple Elements: When a component needs to return sibling elements.
Rendering Lists: To group list items without extra wrapper divs.
Conditional Rendering: To group conditionally rendered elements cleanly.
Syntax:
Shorthand (most common):
<>
<ChildComponent1 />
<ChildComponent2 />
</>
content_copydownload
Use code with caution.Jsx
Full Syntax (for keys):
<React.Fragment>
<ChildComponent1 />
<ChildComponent2 />
</React.Fragment>
content_copydownload
Use code with caution.Jsx
Adding Keys:
Use the full React.Fragment syntax when you need to add key attributes to elements within the fragment (essential for lists).
Example:
<React.Fragment>
{items.map(item => (
<ChildComponent key={item.id} />
))}
</React.Fragment>
content_copydownload
Use code with caution.Jsx
Key Difference from <div>:
<div>: Adds a <div> element to the DOM.
Fragment (<> or <React.Fragment>): Groups elements without adding any element to the DOM.
In summary, use React Fragments to cleanly group elements in your JSX without introducing unnecessary divs or other wrapper elements into the rendered HTML. This leads to a more maintainable and potentially more performant DOM structure.
How do you reset a component's state in React?
In essence: To reset a component's state, you set it back to its initial values. The method varies slightly between functional components (using hooks) and class components.
Key Principle: Re-initialize the state with the original initialState value.
Functional Components (using useState hook):
Define an initialState variable.
Initialize state using useState(initialState).
Create a resetState function that calls setState(initialState).
Example:
const MyComponent = () => {
const initialState = { count: 0, text: '' };
const [state, setState] = useState(initialState);
const resetState = () => {
setState(initialState);
};
// ...
};
content_copydownload
Use code with caution.JavaScript
Class Components:
Define initialState in the constructor.
Set this.state = this.initialState in the constructor.
Create a resetState method that calls this.setState(this.initialState).
Example:
class MyComponent extends Component {
constructor(props) {
super(props);
this.initialState = { count: 0, text: '' };
this.state = this.initialState;
}
resetState = () => {
this.setState(this.initialState);
};
// ...
}
content_copydownload
Use code with caution.JavaScript
Dynamic Initial State:
If initialState depends on props or other dynamic values, create a function getInitialState to calculate it.
Example (Functional Component):
const MyComponent = (props) => {
const getInitialState = () => ({ count: props.initialCount, text: '' });
const [state, setState] = useState(getInitialState);
const resetState = () => {
setState(getInitialState()); // Recalculate initial state
};
// ...
};
content_copydownload
Use code with caution.JavaScript
Important Notes:
Always reset to the original initialState value, not just an empty object or default values, unless that's the intended behavior.
In functional components, be mindful of stale closures if resetState is defined inside an effect and uses external variables. Ensure those variables are in the effect's dependency array if needed.
What is 'use strict';
in JavaScript for?
What are the advantages and disadvantages to using it?
In essence: 'use strict'; enables strict mode in JavaScript, which enforces stricter rules for parsing and error handling. It helps write cleaner, safer, and more maintainable code by preventing common errors and bad practices.
What it is:
A directive introduced in ECMAScript 5 (ES5).
Enables strict mode for either an entire script or an individual function.
Imposes stricter parsing and error handling rules.
How to Use:
Globally (entire script): Place 'use strict'; at the very beginning of your JavaScript file.
Locally (within a function): Place 'use strict'; at the beginning of the function's body.
Advantages:
Prevents Accidental Global Variables: Undeclared variables throw errors instead of being silently created as globals.
Throws Errors for Silent Failures: Assignments that would normally fail silently (like assigning to read-only properties) now throw exceptions.
Prevents Deleting Undeletable Properties: Attempts to delete undeletable properties throw errors.
Unique Parameter Names: Requires function parameters to have unique names.
this is undefined in Global Context: In the global context, this is undefined instead of the global object.
Catches Common Errors: Helps identify and prevent common coding mistakes.
Disables Confusing Features: Restricts the use of poorly designed or error-prone features.
Improved Security: Restricts the use of eval() and prevents the use of deprecated features like arguments.caller and arguments.callee to prevent variable declarations in the calling scope.
Compatibility: Ensures compatibility with future versions of JavaScript by preventing the use of reserved keywords as identifiers.
Disadvantages:
Loss of Some "Sloppy Mode" Features: You can no longer use some of the less-desirable features that developers might have relied on in non-strict mode.
No function.caller and function.arguments: Access to these properties is prohibited.
Concatenation Issues: Combining strict mode and non-strict mode scripts can sometimes cause problems.
Is it "Strictly" necessary?
Not always required now because:
Modules: JavaScript modules (ES6 and Node.js) are automatically in strict mode.
Classes: Code inside class definitions is automatically in strict mode.
Still Recommended: Good practice for most JavaScript code, especially libraries and when supporting older environments.
Irreversible: Once 'use strict'; is set, there is no way to turn it off.
Placement: Must be placed at the very beginning of a file or function.
Overall: The benefits of 'use strict'; generally outweigh the drawbacks. It promotes better coding practices and helps prevent errors. It's a good idea to use it by default in most cases.
Explain AJAX in as much detail as possible
In essence: AJAX (Asynchronous JavaScript and XML) is a technique for creating dynamic and interactive web pages. It allows updating parts of a page with data from the server without reloading the entire page, making web applications feel faster and more responsive.
What is AJAX?
Stands for Asynchronous JavaScript and XML.
A set of techniques to create asynchronous web applications.
Key Idea: Send and receive data from the server in the background without full page reloads.
Originally used XML, but now JSON is more common.
Traditional Web Pages vs. AJAX:
Traditional: Every interaction requires a full page reload from the server.
AJAX: Only parts of the page are updated, making the experience smoother.
How AJAX Works (Modern Approach with fetch() API):
Initiate Request:
Use the fetch() function to make an asynchronous request to a URL.
fetch(url, options):
url: The resource you want to fetch.
options (optional): An object to configure the request (method, headers, body, etc.).
Return a Promise:
fetch() returns a Promise that resolves to a Response object.
Use .then() or async/await to handle the promise.
Handle the Response:
The Response object has methods to extract data:
.json(): Parses the response as JSON.
.text(): Gets the response as plain text.
.blob(): Handles binary data.
Example:
fetch('https://api.example.com/data')
.then(response => response.json()) // Parse as JSON
.then(data => console.log(data)) // Do something with the data
.catch(error => console.error('Error:', error)); // Handle errors
content_copydownload
Use code with caution.JavaScript
Asynchronous Nature:
fetch() is asynchronous: The browser continues other tasks while waiting for the server.
Callbacks (then, catch) are executed when the server responds and the event loop is idle. The callbacks are executed as part of the microtask queue, which takes precedence over the task queue.
Request Options:
The second argument to fetch() allows configuring:
HTTP method (GET, POST, PUT, DELETE, etc.)
Headers (Content-Type, authorization, etc.)
Body (data to send)
Credentials (cookies, etc.)
Caching behavior
Error Handling:
Use .catch() or try/catch (with async/await) to handle network errors or invalid responses.
Older Approach (XMLHttpRequest):
The older way to do AJAX.
More complex and less flexible than fetch().
Example (for reference):
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
console.log(xhr.responseText);
} else {
console.error('Error:', xhr.status);
}
}
};
xhr.open('GET', 'https://api.example.com/data', true); // true for asynchronous
xhr.send();
content_copydownload
Use code with caution.JavaScript
Advantages of AJAX:
Improved User Experience: Makes web pages more dynamic and responsive.
Reduced Bandwidth Usage: Only updates necessary data, not the whole page.
Faster Perceived Load Time: Parts of the page can load and update independently.
Disadvantages of AJAX:
Increased Complexity: Can make code more complex to develop and debug.
Browser Compatibility: Older browsers might have limited support (less of an issue now).
Security Considerations: Requires careful handling of data and requests to prevent vulnerabilities.
Not Ideal for All Situations: Full page reloads are still appropriate in some cases.
In summary, AJAX is a powerful technique for building modern, interactive web applications by enabling asynchronous communication with the server. The fetch() API is the preferred way to implement AJAX in modern JavaScript.
What are React Portals used for?
In essence: React Portals let you render a component's children into a different part of the DOM, outside of its parent's DOM hierarchy. This is primarily used for elements like modals, tooltips, and dropdowns that need to visually "break out" of their parent's layout constraints.
Introduction:
A way to render children into a DOM node that is outside the parent component's DOM hierarchy.
Solves issues where a child component needs to be visually outside its parent's bounds.
Use Cases:
Modals:
Render modals at the top level of the DOM to avoid z-index and overflow issues with the parent.
Ensures modals appear above all other content.
Tooltips:
Prevent tooltips from being clipped by parent containers with overflow: hidden or similar styles.
Allows for precise positioning relative to the target element.
Dropdowns:
Similar to tooltips, prevents clipping and allows dropdown menus to extend beyond the parent's boundaries.
How to Create a Portal:
Use ReactDOM.createPortal(child, container):
child: The React element you want to render (e.g., a modal, tooltip).
container: The DOM node where you want to render the child (e.g., document.body, a dedicated <div> at the top level).
Example (Modal):
const Modal = ({ isOpen, children }) => {
if (!isOpen) return null;
return ReactDOM.createPortal(
<div className="modal">{children}</div>,
document.getElementById('modal-root') // Render into a specific <div>
);
};
content_copydownload
Use code with caution.JavaScript
Benefits:
Break Out of Parent Constraints: Avoid z-index wars, overflow clipping, and other layout issues caused by the parent's styles.
Improved Accessibility: Makes elements like modals and tooltips easier for screen readers to access by placing them at the top level of the DOM.
Simplified Styling: Avoids complex CSS workarounds to position elements that need to appear outside their parent's boundaries.
Key Idea: Although the component is rendered somewhere else in the DOM using Portals, it still behaves as a normal React component within the React tree (e.g., it still receives props and context from its React parents).
In summary, React Portals are a powerful tool for rendering components outside their parent's DOM hierarchy. They are essential for creating UI elements that need to visually break out of their parent's layout, ensuring proper functionality, accessibility, and styling.
What are the advantages and disadvantages of using AJAX?
In essence: AJAX improves user experience and website performance by enabling asynchronous data updates without full page reloads. However, it adds complexity, has potential security risks, and can create challenges for SEO and navigation if not implemented carefully.
What is AJAX?
Asynchronous JavaScript and XML.
A technique for updating parts of a web page without reloading the entire page.
Now often uses JSON instead of XML.
Advantages:
Enhanced User Experience:
Creates smoother, more responsive web applications.
Avoids jarring full-page reloads for every interaction.
Ideal for applications like chat, email, and live updates.
Reduced Server Load and Bandwidth:
Transfers only necessary data, not the entire page.
Leads to faster loading times and less strain on the server.
Improved Performance:
Faster data exchange and partial updates make the application feel quicker.
Dynamic Content Updates:
Enables real-time updates without page reloads (e.g., live scores, stock tickers).
Client-only states like form input values are maintained.
Form Validation:
Enables asynchronous form validation, providing immediate feedback without full-page reloads.
Disadvantages:
Increased Complexity:
More complex to develop and debug than traditional web applications.
Requires handling asynchronous operations and potential race conditions.
Pages can become out of sync without proper state management.
Dependency on JavaScript:
Doesn't work if JavaScript is disabled or not supported.
Requires fallback mechanisms for basic functionality.
Security Concerns:
Introduces potential security vulnerabilities like Cross-Site Scripting (XSS) if not handled carefully.
Requires proper data validation and sanitization.
Browser Support:
Older browsers may have limited or no support for AJAX.
Requires compatibility testing and potentially polyfills.
SEO Challenges:
Search engines may struggle to index dynamically loaded content.
Requires techniques like server-side rendering or careful content structuring.
Navigation Problems:
Can break the browser's back/forward buttons and bookmarking.
The URL doesn't always reflect the current state of the page.
State Management:
Maintaining application state and history can be complex.
May require using the History API or URL hash fragments.
In summary, AJAX offers significant benefits for creating dynamic and responsive web applications, but developers need to carefully consider the added complexity, security implications, and potential challenges for SEO, navigation, and browser compatibility.
What are the differences between XMLHttpRequest
and fetch()
in JavaScript and browsers?
In essence: Both XMLHttpRequest and fetch() are used for making HTTP requests (AJAX). fetch() is generally preferred in modern JavaScript due to its cleaner, Promise-based syntax, and more powerful features. XMLHttpRequest is older and uses event listeners.
Key Differences:
Feature | XMLHttpRequest (XHR) | fetch() |
Syntax | Event-driven, uses event listeners | Promise-based, uses .then() and .catch() |
Error Handling | onerror event | .catch() method for handling errors in the Promise chain |
Headers | setRequestHeader() method | Headers object in the options (second argument to fetch()) |
Request Body | send() method with data | body property in the options object |
Response Handling | responseType to indicate expected response format | Unified Response object with methods like .json(), .text(), .blob() |
Caching | Manual caching control is difficult | cache option in the second parameter ('default', 'no-store', 'reload', etc.) |
Cancelation | abort() method | AbortController and signal in the options object |
Progress | onprogress event for upload/download progress | No built-in progress tracking. Can be implemented by inspecting Response.body but it is complicated |
Node.js Support | Not natively supported | Supported |
XMLHttpRequest Example:
const xhr = new XMLHttpRequest();
xhr.open('GET', 'url', true);
xhr.responseType = 'json';
xhr.onload = () => {
if (xhr.status === 200) {
console.log(xhr.response);
}
};
xhr.onerror = () => { console.error("Error"); };
xhr.send();
content_copydownload
Use code with caution.JavaScript
fetch() Example:
fetch('url')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
content_copydownload
Use code with caution.JavaScript
Other Considerations:
fetch() is generally preferred for modern web development.
XMLHttpRequest has better support for progress tracking, but fetch() does not.
XMLHttpRequest is only available in the browser, fetch() is available in most JavaScript environments.
In summary, fetch() provides a more modern, flexible, and Promise-based approach to making HTTP requests compared to the older event-driven XMLHttpRequest. Choose fetch() unless you need progress events or have specific compatibility requirements with very old browsers.
How do you abort a web request using AbortController
in JavaScript?
In essence: AbortController provides a way to cancel asynchronous operations, like fetch() requests. You create an AbortController, get its signal, pass the signal to the request, and then call controller.abort() to cancel it.
Why Abort Requests?
User Actions: Cancel requests based on user input (e.g., a cancel button).
Prioritize Requests: In a series of requests, prioritize the latest one and cancel older ones (e.g., type-ahead search).
Resource Management: Cancel requests that are no longer needed (e.g., user navigates away), preventing unnecessary work and potential memory leaks.
How to Use AbortController:
Create an AbortController instance:
const controller = new AbortController();
content_copydownload
Use code with caution.JavaScript
Get the signal:
const signal = controller.signal;
content_copydownload
Use code with caution.JavaScript
Pass the signal to the request (e.g., fetch()):
fetch(url, { signal }) // Add the signal to the request options
.then(response => { /* Handle response */ })
.catch(error => {
if (error.name === 'AbortError') {
console.log('Request aborted'); // Handle the abort
} else {
console.error('Other error:', error);
}
});
content_copydownload
Use code with caution.JavaScript
Call abort() to cancel the request:
controller.abort();
content_copydownload
Use code with caution.JavaScript
Example:
const controller = new AbortController();
const signal = controller.signal;
fetch('https://jsonplaceholder.typicode.com/todos/1', { signal })
.then(response => { /* Handle response */ })
.catch(error => {
if (error.name === 'AbortError') {
console.log('Request aborted');
} else {
console.error('Error:', error);
}
});
// Later, to cancel the request:
controller.abort();
content_copydownload
Use code with caution.JavaScript
Use Case Examples:
User Cancels Action: A button to cancel an upload.
Type-Ahead Search: Cancel previous requests when the user types a new character.
Navigation: Cancel requests when the user leaves the page.
Important Notes:
AbortController is not limited to fetch(); it can be used with other asynchronous operations.
You can reuse the same AbortController to cancel multiple requests at once.
controller.abort() does not notify the server. The server continues processing the request until it's done or times out. The browser just ignores the response.
In summary, AbortController gives you a clean way to cancel in-progress web requests, improving user experience and resource management. It's a valuable tool for handling asynchronous operations in modern JavaScript.
What are JavaScript polyfills for?
In essence: Polyfills are pieces of JavaScript code that provide modern functionality to older browsers that don't natively support those features. They let you use new language features and APIs while still supporting older environments.
What are Polyfills?
Code (usually JavaScript) that implements a feature on older browsers that don't support it natively.
"Fill in" the gaps in older browser functionality.
Allow developers to use modern JavaScript features and APIs without worrying about compatibility.
How Polyfills Work:
Feature Detection: Check if the browser supports the feature you want to use (e.g., using typeof, in, or checking window properties).
Conditional Implementation: If the feature is missing, the polyfill code is executed, providing a custom implementation using existing JavaScript capabilities.
Example (Array.prototype.includes):
// Polyfill for Array.prototype.includes (not supported in IE 11)
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement) {
// ... custom implementation using a loop ...
for (var i = 0; i < this.length; i++) {
if (this[i] === searchElement) {
return true;
}
}
return false;
};
}
content_copydownload
Use code with caution.JavaScript
Common Use Cases:
New JavaScript Methods: Array.prototype.includes(), String.prototype.startsWith(), Object.assign(), etc.
New APIs: fetch(), Promise, IntersectionObserver, Web Components, etc.
Implementing Polyfills:
Identify Missing Feature: Determine which features need polyfilling.
Write/Find Fallback: Create or find a polyfill that provides the missing functionality.
Test Thoroughly: Ensure the polyfill works correctly across different browsers.
Apply Conditionally: Use feature detection to load the polyfill only when needed.
Considerations:
Selective Loading: Load polyfills only for browsers that require them.
Feature Detection: Always use feature detection before applying a polyfill.
Size and Performance: Minimize and compress polyfills to reduce their impact on page load times.
Existing Libraries: Consider using libraries like core-js or services like Polyfill.io.
Libraries and Services:
core-js: A modular library with polyfills for many ECMAScript features.
import 'core-js/actual/array/flat-map'; // Polyfills Array.prototype.flatMap
content_copydownload
Use code with caution.JavaScript
Polyfill.io: A service that provides polyfills based on the browser's User-Agent.
<script src="https://polyfill.io/v3/polyfill.min.js"></script>
content_copydownload
Use code with caution.Html
In summary, polyfills are crucial for web development because they allow developers to use modern JavaScript features while still supporting older browsers. They bridge the gap between the latest language standards and the realities of browser compatibility.
Why is extending built-in JavaScript objects not a good idea?
In essence: Extending built-in objects (like Array, String, Object) can lead to conflicts with future JavaScript updates, other libraries, and makes code harder to maintain. It's like modifying a core part of the language, which can have unintended consequences.
What is Extending Built-in Objects?
Adding new properties or methods to the prototype of built-in objects.
Example:
String.prototype.reverseString = function() {
return this.split('').reverse().join('');
};
content_copydownload
Use code with caution.JavaScript
Why It's Generally a Bad Idea:
Future-Proofing/Collisions:
Future JavaScript versions might add methods with the same name, overwriting your extension or vice versa. This is what happened with MooTools' Array.prototype.contains and the standard Array.prototype.includes in ES6, leading to many broken websites.
Different libraries might extend the same object with the same method name but different implementations, leading to conflicts and unpredictable behavior.
Maintenance and Debugging:
Makes it harder for other developers to understand your code because the built-in objects behave differently than expected.
Difficult to track down bugs caused by conflicting extensions.
Performance:
Can negatively impact performance if extensions are not optimized.
Security:
Can introduce security vulnerabilities if not done carefully.
Compatibility:
Extensions might not be compatible with all browsers or environments.
Namespace Clashes:
Multiple libraries extending the same object can cause naming conflicts.
Alternatives to Extending Built-in Objects:
Create Custom Utility Functions:
function reverseString(str) {
return str.split('').reverse().join('');
}
content_copydownload
Use code with caution.JavaScript
Use Libraries/Frameworks: Many libraries provide helper functions that avoid modifying built-in objects.
Composition/Inheritance: Create new classes or objects that inherit from built-in objects without modifying them directly.
Valid Exception: Polyfills:
Polyfills are a legitimate reason to extend built-in objects.
They provide implementations of newer JavaScript features for older browsers that don't support them.
Example: core-js is a popular library for polyfills.
In summary, avoid extending built-in JavaScript objects unless you're creating a well-tested polyfill. It's generally safer and more maintainable to create custom utility functions, use existing libraries, or use composition to achieve the desired functionality without modifying core language objects.
Why is it, in general, a good idea to leave the global JavaScript scope of a website as-is and never touch it?
In essence: Modifying the global scope (the window object in browsers) can lead to naming conflicts, code that's hard to maintain, security risks, and compatibility issues. It's like leaving your belongings everywhere in a shared house – it creates a mess and causes problems for everyone.
What is the Global Scope?
The top-level scope in JavaScript.
In browsers, it's the window object.
Variables and functions declared outside any function or block (and not in a module) become properties of the global object.
Why Avoid Touching the Global Scope?
Naming Conflicts:
Different scripts or libraries might use the same global variable names, leading to overwrites and unexpected behavior.
Cluttered Global Namespace:
Makes code harder to manage and understand as the project grows.
Scope Leaks (Memory Leaks):
Accidental references to global variables in closures or event handlers can prevent garbage collection, leading to memory leaks.
Modularity and Encapsulation:
Global variables break encapsulation, making code less organized, reusable, and maintainable. It becomes unclear what parts of the codebase depend on other parts.
Security Concerns:
Global variables are accessible to any script on the page, including potentially malicious ones. Sensitive data should not be stored globally.
Compatibility and Portability:
Code relying heavily on global variables is less portable and harder to integrate with other libraries or environments.
Example of Global Scope Pollution:
// In the global scope (not in a module)
let count = 0; // Global variable
function incrementCount() {
count++; // Modifies the global count
}
content_copydownload
Use code with caution.JavaScript
Best Practices to Avoid Global Scope Pollution:
Use Local Variables: Declare variables with let or const within functions or blocks.
Pass Variables as Parameters: Pass data explicitly to functions instead of relying on global variables.
Use Immediately Invoked Function Expressions (IIFEs):
(function() {
let count = 0; // Not global, only accessible inside the IIFE
window.incrementCount = function() { // Exposing a function to global scope
count++;
};
})();
content_copydownload
Use code with caution.JavaScript
Use Modules (Recommended):
Modules have their own scope, preventing variables from leaking into the global scope.
ES Modules (import/export) are standard in modern JavaScript.
This provides a way to encapsulate the underlying data and only expose the necessary operations – no direct manipulation of the value is allowed.
In summary, keeping the global scope clean is crucial for writing maintainable, secure, and robust JavaScript code. Minimize global variables, use local scope, embrace modules, and follow best practices to avoid polluting the global namespace.
What are higher order components in React?
In essence: A Higher-Order Component (HOC) is a function that takes a component and returns a new component with added features or modified behavior. It's a way to reuse component logic, like a decorator for components.
Definition:
A function that accepts a component (the "Wrapped Component") as input.
Returns a new component that usually renders the Wrapped Component with extra props or modified behavior.
Purpose:
Reuse Component Logic: Share common functionality between multiple components without repeating code.
Enhance Components: Add extra props, state, or behavior to existing components.
Abstract Away Boilerplate: Isolate common patterns (like data fetching or authentication) into reusable HOCs.
Example:
// HOC: withExtraProp
const withExtraProp = (WrappedComponent) => {
return (props) => {
return <WrappedComponent {...props} extraProp="I'm an extra prop!" />;
};
};
// Component: MyComponent
const MyComponent = (props) => {
return <div>{props.extraProp}</div>; // Can access extraProp
};
// Enhanced Component:
const EnhancedComponent = withExtraProp(MyComponent);
// Usage:
<EnhancedComponent /> // Renders MyComponent with the extra prop
content_copydownload
Use code with caution.JavaScript
Common Use Cases:
Authentication: Redirect unauthenticated users.
Authorization: Restrict access to certain components based on user roles.
Logging: Log component renders or prop changes.
Theming: Inject theme-related props (colors, styles).
Data Fetching: Fetch data and pass it as props to the wrapped component.
Conditional Rendering: Control whether the wrapped component renders based on some condition.
Best Practices:
Don't Mutate the Original Component: Always return a new component.
Pass Through Props: Use the spread operator (...props) to pass original props to the wrapped component.
Descriptive Naming: Use names that clearly indicate the HOC's purpose (e.g., withAuthentication, withLogging).
Use Sparingly: Overusing HOCs can lead to complex component hierarchies ("wrapper hell"). Consider hooks as an alternative.
Compose HOCs: You can chain multiple HOCs together to add multiple enhancements.
Alternatives:
Render Props: A component with a render prop that is a function, allowing the consumer to control what's rendered.
Hooks: useState, useEffect, and custom hooks offer alternative ways to share logic, especially in functional components.
In summary, HOCs are a powerful pattern for reusing component logic in React. They act like decorators, enhancing existing components with new features. However, consider hooks as a more modern alternative for many use cases where HOCs were traditionally used.
Explain the differences between CommonJS modules and ES modules in JavaScript
In essence: CommonJS and ES modules are two different ways to organize and share JavaScript code. CommonJS is older, primarily used in Node.js, and loads modules synchronously. ES modules are the newer standard, work in browsers and Node.js, and load modules asynchronously.
What are Modules?
Reusable pieces of code that encapsulate functionality.
Promote code organization, maintainability, and reusability.
CommonJS:
Older module system, originally designed for Node.js (server-side).
require() function to import modules.
module.exports or exports object to export values.
Synchronous loading: Modules are loaded one after another, in order.
Dynamic: require() can be called anywhere, even conditionally.
File extension: .js (usually)
Not natively supported in browsers (requires bundling tools like Webpack or Browserify).
// my-module.js (CommonJS)
const value = 42;
module.exports = { value };
// main.js (CommonJS)
const myModule = require('./my-module.js');
console.log(myModule.value); // 42
content_copydownload
Use code with caution.JavaScript
ES Modules (ECMAScript Modules):
Newer, standardized module system introduced in ES6 (ES2015).
import statement to import modules.
export statement to export values.
Asynchronous loading: Modules can be loaded in parallel, potentially improving performance.
Static: import and export must be at the top level (not inside conditions or functions).
File extension: .mjs or .js (with "type": "module" in package.json).
Natively supported in modern browsers.
Better for tree-shaking: Unused code can be more easily eliminated during bundling, resulting in smaller file sizes.
// my-module.mjs (ES Module)
export const value = 42;
// main.mjs (ES Module)
import { value } from './my-module.mjs';
console.log(value); // 42
content_copydownload
Use code with caution.JavaScript
Key Differences Summarized:
Feature | CommonJS | ES Modules |
Syntax | require(), module.exports | import, export |
Environment | Primarily Node.js | Browsers and Node.js |
Loading | Synchronous | Asynchronous |
Structure | Dynamic | Static |
File Extension | .js (usually) | .mjs or .js (with "type": "module" in package.json) |
Browser Support | No (requires bundlers) | Yes (modern browsers) |
Optimization | Less optimizable | More optimizable (tree-shaking) |
Which to Use?
ES modules are generally preferred for new projects because of their browser support, static analysis (which enables tree-shaking), and asynchronous loading.
CommonJS is still widely used in existing Node.js codebases.
In summary, ES modules are the modern standard for JavaScript modules, offering advantages in terms of performance, tooling, and browser compatibility. While CommonJS is still relevant in the Node.js ecosystem, ES modules are the future of JavaScript modules.
Explain one-way data flow of React and its benefits
In essence: In React, data flows in one direction: from parent components down to child components through props. This makes the application's data flow predictable, easier to understand, and debug.
What is One-Way Data Flow?
Data flows in a single direction: from parent to child components.
Props are used to pass data from parent to child.
Child components can only read props, not modify them directly.
For a child to update data, it must call a function passed down from the parent via props.
Example:
// ParentComponent.jsx
import React, { useState } from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
const [data, setData] = useState('Hello from Parent');
const handleChange = (newData) => {
setData(newData);
};
return (
<div>
<h1>{data}</h1>
<ChildComponent data={data} onChange={handleChange} />
</div>
);
};
export default ParentComponent;
// ChildComponent.jsx
import React from 'react';
const ChildComponent = ({ data, onChange }) => {
return (
<div>
<p>{data}</p>
<button onClick={() => onChange('Hello from Child')}>Change Data</button>
</div>
);
};
export default ChildComponent;
content_copydownload
Use code with caution.JavaScript
ParentComponent owns the data state.
ChildComponent receives data and the handleChange function as props.
ChildComponent cannot directly change data; it calls onChange (which is handleChange in the parent) to request an update.
Benefits of One-Way Data Flow:
Improved Maintainability:
Easier to understand how data changes over time.
Code is more predictable and organized.
Easier Debugging:
Simpler to trace the source of data changes and identify bugs.
You can follow the data flow from parent to child to find issues.
Better Performance:
Reduces the complexity of data management.
React can efficiently update the UI by knowing exactly where data changes originate.
One-Way vs. Two-Way Data Binding:
One-Way (React): Parent controls data; children receive data via props and request changes via callbacks.
Two-Way (e.g., Angular): Changes in the UI can directly update the underlying data, and vice-versa. Two-way binding can be more complex to manage in large applications.
In summary, one-way data flow is a core principle in React that promotes a clear, predictable, and maintainable application structure. By enforcing a unidirectional flow of data, React makes it easier to reason about your application's state and manage changes efficiently.
What are iterators and generators in JavaScript and what are they used for?
In essence: Iterators provide a standard way to access elements of a collection sequentially. Generators are special functions that can pause and resume their execution, making them ideal for creating iterators and handling asynchronous operations in a more manageable way.
Iterators:
Definition: Objects that define a sequence and provide a next() method to access the next item in the sequence.
next() method:
Returns an object with two properties:
value: The next value in the sequence.
done: A boolean indicating if the iteration is complete (true) or not (false).
Example of iterator interface:
const iterator = {
current: 0,
last: 5,
next() {
if (this.current <= this.last) {
return { value: this.current++, done: false };
} else {
return { value: undefined, done: true };
}
},
};
content_copydownload
Use code with caution.JavaScript
Use Cases:
Making custom objects iterable (usable with for...of loops, spread operator).
Providing a standard way to traverse different data structures.
Lazy evaluation: Processing elements only when needed.
Implementing Iterators:
Add a [Symbol.iterator] method to your object that returns an iterator object with a next() method.
Built-in Iterables: Arrays, Strings, Maps, Sets, NodeLists are iterable by default.
Generators:
Definition: Special functions that can pause and resume their execution.
Declared with function*.
Use the yield keyword to pause and return a value.
When called, a generator function returns an iterator object.
Example:
function* numberGenerator() {
let num = 0;
while (num <= 5) {
yield num++;
}
}
const gen = numberGenerator();
console.log(gen.next()); // { value: 0, done: false }
console.log(gen.next()); // { value: 1, done: false }
// ...
content_copydownload
Use code with caution.JavaScript
Use Cases:
Creating iterators: Generators simplify creating iterators (compared to manually implementing the iterator protocol).
Lazy Evaluation: Generate values on demand, saving memory and improving performance for large datasets.
Asynchronous Operations: Make asynchronous code look more synchronous (especially when combined with async/await).
Iterating over data streams: Such as fetching data from an API or reading files.
Implementing asynchronous iterators: Useful for handling asynchronous data sources.
Simplifying complex control flow: Generators can be used to represent state machines or implement coroutines.
Generators vs. Regular Functions:
Regular functions: Execute from start to finish when called.
Generators: Can pause at each yield statement and resume later.
Benefits of Generators:
Memory Efficiency: Values are generated on demand.
Improved Code Readability: Can make complex iteration logic easier to follow.
Flexibility: Can be used for both synchronous and asynchronous tasks.
Example: Implementing Range with a Generator:
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
*[Symbol.iterator]() {
for (let i = this.start; i <= this.end; i++) {
yield i;
}
}
}
for (const num of new Range(1, 3)) {
console.log(num); // 1, 2, 3
}
content_copydownload
Use code with caution.JavaScript
In summary, iterators and generators are powerful tools in JavaScript for working with sequences of data. Iterators provide a standard interface for iteration, while generators offer a concise and efficient way to create iterators and manage asynchronous operations.
Explain the difference between mutable and immutable objects in JavaScript
In essence: Mutable objects can be changed after they are created (like arrays and regular objects), while immutable objects cannot be changed once created (like strings, numbers, and frozen objects). Immutability is a core concept in functional programming and can lead to more predictable and maintainable code.
Mutable Objects:
Definition: Objects whose properties and values can be modified after creation.
Default for objects and arrays in JavaScript.
Changes to a mutable object directly affect the original object in memory.
Example:
const mutableObject = { name: 'John', age: 30 };
mutableObject.name = 'Jane'; // Modifies the original object
console.log(mutableObject); // Output: { name: 'Jane', age: 30 }
content_copydownload
Use code with caution.JavaScript
Immutable Objects:
Definition: Objects whose properties and values cannot be changed after creation.
Primitive data types (string, number, boolean, null, undefined, symbol) are inherently immutable.
Any operation that appears to modify an immutable object actually creates a new object.
Example (string - a primitive):
let str = "hello";
str.toUpperCase(); // Does not change str
console.log(str); // Output: "hello"
str = str.toUpperCase(); // Assigns a new string to str
console.log(str); // Output: "HELLO"
content_copydownload
Use code with caution.JavaScript
Example (creating an immutable object with Object.freeze()):
const immutableObject = Object.freeze({ name: 'John', age: 30 });
immutableObject.name = 'Jane'; // Fails silently (no error, no change) in non-strict mode. Throws error in strict mode.
console.log(immutableObject); // Output: { name: 'John', age: 30 }
content_copydownload
Use code with caution.JavaScript
const vs. Immutability:
const prevents reassignment of a variable, but it does not make the object it holds immutable (unless it's a primitive).
You can still modify properties of an object declared with const.
Example:
const obj = { name: 'John' };
obj.name = 'Jane'; // Allowed
console.log(obj); // Output: { name: 'Jane'}
// obj = { name: 'Alice' }; // Error: Assignment to constant variable (reassignment not allowed)
content_copydownload
Use code with caution.JavaScript
Ways to Achieve Immutability (for Objects):
Object.freeze(): Makes an object shallowly immutable (nested objects can still be modified).
Object.defineProperty(): Can make individual properties immutable using writable: false and configurable: false.
Object.seal(): Prevents adding or deleting properties, but allows modifying existing ones.
Object.preventExtensions(): Prevents adding new properties.
Libraries: Immer, Immutable.js provide persistent immutable data structures and efficient methods for working with them.
Pros of Immutability:
Easier to Reason About: Makes code more predictable and easier to understand.
Simplified Change Detection: Makes it easy to detect changes (referential equality).
Easier Debugging: Reduces side effects and makes it easier to track down bugs.
Concurrency: Immutable objects are inherently thread-safe.
No Need for Defensive Copying: You can safely share immutable objects without worrying about unintended modifications.
Cons of Immutability:
Can be complex to implement from scratch: Requires creating new objects for every change. Use libraries like Immer or Immutable.js to make it easier.
Potential Performance Overhead: Creating new objects can have performance implications. However, libraries use structural sharing to mitigate this.
Difficult to implement cyclic data structures: Cyclic data structures such as graphs are difficult to implement using immutability.
In summary, understanding the difference between mutable and immutable objects is crucial for writing robust and maintainable JavaScript code. While mutability is the default for objects and arrays, immutability offers significant benefits in terms of predictability, debugging, and concurrency. Libraries like Immer and Immutable.js can help you work with immutable data structures efficiently.