DEV Community

Cover image for Essential Features & Concepts in Frontend You Must Know Before Technical Interviews
Ryoichi Homma
Ryoichi Homma

Posted on

Essential Features & Concepts in Frontend You Must Know Before Technical Interviews

As I am preparing for a technical job interview for a frontend engineer position, I have decided to brush up on my frontend domain knowledge by writing this article.

Agenda

  1. JavaScript Foundational Concepts
  2. ES5 vs. ES6
  3. TypeScript vs. JavaScript
  4. React Features
  5. Vue Features
  6. Recommended Resource

1. JavaScript Foundational Concepts:

1.1. DOM Methods

DOM method is an action or function that can be performed on elements within the Document Object Model (DOM) of a web page. The DOM represents the structure of an HTML document as a tree of objects, where each part of the document (like elements, attributes, text) is a node in this tree.

  • document.getElementsByTagName()
    • This method returns a live HTMLCollection of all child elements with the specified tagName.
    • The tagName argument should be a string representing the HTML tag name (e.g., "div", "p", "a", "img").
    • It selects all elements that match the given tag name, regardless of their class or ID.
const divs = document.getElementsByTagName('div');
Enter fullscreen mode Exit fullscreen mode
  • document.getElementsByClassName()
    • This method returns a live HTMLCollection of all child elements that have all of the specified className.
    • The className argument should be a string representing one or more class names, separated by spaces if multiple classes are targeted (e.g., 'my-class', 'main btn').
    • It selects elements based on their assigned CSS classes.
// select all elements with the class 'highlight'
const highlightedElements = document.getElementsByClassName('highlight'); 
// select all elements with both 'card' and 'active' classes
const activeCards = document.getElementsByClassName('card active'); 
Enter fullscreen mode Exit fullscreen mode

1.2. Array Methods

Array.prototype.**() is a higher-order array method in JavaScript that provide functional ways to manipulate arrays.

  • Array.prototype.map() creates a new array by applying a provided function to each element in the calling array. The new array will have the same length as the original array, but its elements will be the results of the callback function. It is used for transforming each element of an array.
const nums = [1, 2, 3]; 
const doubleNums = nums.map(num => num * 2); // return [2, 4, 6]
Enter fullscreen mode Exit fullscreen mode
  • Array.prototype.filter() creates a new array containing only the elements for which the provided callback function returns a truthy value. It is used for selecting a subset of elements from an array based on a condition. The new array's length may be less than or equal to the original array's length.
const nums = [1, 2, 3, 4, 5]; 
const oddNums = nums.filter(num => num % 2 !== 0); // return [1, 3, 5]
Enter fullscreen mode Exit fullscreen mode
  • Array.prototype.reduce() executes a reducer callback function on each element of the array, resulting in a single output value. This value can be a number, a string, an object, an array, or any other type. It is used for accumulating a single value from an array. It takes an optional initialValue for the accumulator.
const nums = [1, 2, 3, 4, 5]; 
const sum = nums.reduce((accumulator, current) => accumulator + current, 0); // return 15
Enter fullscreen mode Exit fullscreen mode

Summary

  • map is for transforming (one-to-one mapping of elements).
  • filter is for selection (creating a subset based on a condition).
  • reduce is for aggregation (reducing an array to a single value).

1.3. == vs. ===

  • == (Abstract Equality): this operator compares values for equality after performing type coercion. If the two operands are different types, JavaScript will try to convert one or both operands to a common type before making the comparison.

  • === (Strict Equality): this operator compares both the value and the type of the operands. No type coercion is performed. For the comparison to be true, both the value and the data type must be identical.

For reliable and predictable code, it's a best practice to use the strict equality operator (===) as it prevents unexpected behavior from implicit type conversions.

1.4. Bearer

Bearer is used in the Authorization header to specify the type of token being sent in the Authentication header for authentication. It tells the server that the value following Bearer is a bearer token, which is a security token granting access to protected resources.

How the Bearer is beneficial

  • Standardized Authentication: Bearer tokens are widely used in APIs for secure, stateless authentication.
  • Simplicity: the client only needs to include the token; the server validates it without extra steps.
  • Security: tokens can be short-lived and easily revoked, reducing risk if compromised.

Summary
Using Bearer makes authentication secure, simple, and compatible with modern API standards.

2. ES5 vs. ES6:

ES6 introduced numerous new features and syntax enhancements aimed at making JavaScript development more efficient, readable, and maintainable compared to ES5.

2.1. Key Differences

  • Variable Declarations: ES5 primarily used 'var' for variable declarations, which have function-level scope. ES6 introduced let for block-scoped variables and const for block-scoped constant variables, improving scope management and preventing accidental reassignments.

    • var is the old way of declaring variables. var declarations are function-scoped and can be re-declared and re-assigned. This can lead to unexpected behavior and is generally avoided in modern development.
    • let declarations are block-scoped. This means a variable declared with let is only accessible within the block of code (e.g., inside {}) it was defined in. You can re-assign a let variable, but you cannot re-declare it in the same scope.
    • const is for declaring variables that are block-scoped and cannot be re-assigned. The value must be initialized at the time of declaration. While the variables themselves can't be re-assigned, if the value is an object or array, its properties or elements can still be mutated.
  • Arrow Functions: ES6 introduced arrow functions, providing a more concise syntax for writing function expressions and handling this context more predictably. ES5 relied on traditional function keyword syntax.

  • Classes: ES6 introduced the class keyword, offering a more familiar and structured syntax for defining object-oriented structures, similar to other object-oriented languages. ES5 simulated class-like behavior using constructor functions and prototypes.

  • Promises: ES6 introduced Promises for handling asynchronous operations, providing a cleaner and more structured approach compared to the callback-based approach, often leading to "callback hell" in ES5.

2.2. Promise vs. async/await

Promises

Promises are objects that represent the result of asynchronous processing and its value, whether the process succeeded (resolved) or failed (rejected).

  • Pending: this initial state; the operation has not yet completed.
  • Fulfilled: the operation completed successfully.
  • Rejected: the operation failed.

You chain .then() and .catch() methods to a Promise to handle the successful and failed outcomes, respectively.

fetch('https://api.example.com/data')
  .then(res => {
    if (!res.ok) {
      throw new Error('Network response was not okay'); 
    } 
    return res.json(); 
  })
  .then(data => console.log(data))
  .catch(error => console.error('There was a problem with the fetch operation:', error)); 
Enter fullscreen mode Exit fullscreen mode
  • Promise.all() is used to wait for all promises to be completed.
  • Promise.any() is used to return a resolved (succeeded) value once any of the initial promises is resolved (succeeded).

async/await

The async/await is a modern JS feature that provides a cleaner, more readable way to work with Promises.

  • The async is used to declare an asynchronous function. This function automatically returns a Promise.
  • The await is used inside an async function to pause the execution of the function until the Promise it's waiting on is settled (either fulfilled or rejected).

Error handling with async/await is done using a traditional try...catch block, which is familiar to developers from synchronous code.

async function fetchData() {
  try {
    const res = await fetch('https://api.example.com/data'); 
    if (!res.ok) {
      throw new Error('Network response was not okay'); 
    }
    const data = await res.json(); 
    console.log(data); 
  } catch (error) {
    console.error('There was a problem with the fetch operation:', error); 
  }
} 

fetchData(); 
Enter fullscreen mode Exit fullscreen mode

Summary
async/await doesn't replace Promises; it provides a more intuitive and powerful way to use them. It's the preferred method for handling modern asynchronous JavaScript, as it makes the code much cleaner and easier to read.

2.3 Why do we need asynchronous functions?

We need asynchronous functions to perform operations that take time without blocking the main program threads. This is crucial for maintaining a responsive user experience, especially in applications that handle tasks like fetching data from a server, reading a file from the disk, or executing a long-running calculation.

Problem with synchronous code

In a synchronous programming mode, code is executed line by line. That is, when a function or operation is called, the program waits for it to complete before moving to the next line. If a long-running task is initiated, the entire program becomes unresponsive. For a web browser, this means the user interface freezes—the user can't click buttons, type in a field, or see animations.

Solution: asynchronous functions

Asynchronous functions allow the program to initiate a task and continue executing other code without waiting for the task to finish. The program is notified once the task is complete, at which point it can handle the result. This non-blocking behavior is essential for modern applications.

3. TypeScript vs. JavaScript:

TypeScript (TS) is a superset of JavaScript (JS) that adds static typing to the language. This means you can define the types of variables, function parameters, and return values, which helps catch errors during development rather than at runtime. JS, on the other hand, is a dynamically typed language, which means type checking happens only when the code is executed.

3.1. Why Choose TypeScript?

TS is particularly valuable for large, complex, or long-term projects. The static typing provides a safety net that helps prevent a common class of bugs. It also makes the code more self-documenting, as the type definitions can explain what kind of data a function expects and returns. Many popular frameworks and libraries were built with TS, and it is widely used in enterprise-level applications.

3.2. Type Interface

In TypeScript, a type interface refers to an interface declaration, which is used to define the shape or structure of an object, specifying the properties and methods that an object must have.

Why the interfaces are useful

Interfaces are a powerful tool for ensuring code consistency and safety. They help enforce that any object you use in a specific context has a predictable shape.

  • Type Checking: the compiler uses interfaces to check if an object conforms to the defined structure at compile-time. If it doesn't, you get an immediate error, preventing a common class of bugs.

  • Code Documentation: an interface acts as a form of self-documentation. Other developers can look at an interface and immediately understand what an object is supposed to look like.

  • Predictability and Autocomplete: when your IDE knows the structure of an object through an interface, it can offer smart code completion and helpful suggestions, making development faster and less prone to typos.

How the interface works

// 1. Define the interface
interface User {
  id: number;
  name: string;
  email?: string; // The '?' makes this property optional
}

// 2. Use the interface to define a variable
const user1: User = {
  id: 1,
  name: 'Alice',
  email: 'alice@example.com'
};

// 3. This would cause a compile-time error because 'id' is missing
const user2: User = {
  name: 'Bob',
  email: 'bob@example.com'
};
Enter fullscreen mode Exit fullscreen mode

In this example, the User interface dictates that any object of type User must have a number called id and a string called name. If you try to create an object that doesn't meet this contract, the TypeScript compiler will immediately flag an error.

4. React Features:

4.1. Prop Drilling

Prop drilling is a term used in component-based frameworks like React to describe the process of passing data from a parent component down to a deeply nested child component.

How prop drilling works

Imagine you have a component tree like this:
App -> ParentComponent -> ChildComponent -> GrandchildComponent

Suppose the App component holds a piece of data like a username that is only needed by the GrandchildComponent. To get the username from the App component to the GrandchildComponent, you have to drill it down through the intermediate components.

  1. App passes the user prop to ParentComponent.
  2. ParentComponent receives the user prop, but doesn't use it. It simply passes it on to ChildComponent.
  3. ChildComponent also receives the user prop and doesn't use it again. It passes it on to GrandchildComponent.
  4. Finally, GrandchildComponent receives the user prop and uses it to display the username.

4.2. Props vs. State

In React, props are data passed from a parent component to a child component, acting as read-only arguments, while state is data managed internally by a component that can change over time, triggering a re-render. Props provide data to customize child components, whereas state allows a component to manage its own local, dynamic information, such as user inputs or API data.

4.3. Virtual DOM

The Virtual DOM (VDOM) is a lightweight, in-memory representation of the real DOM (Document Object Model). It's a key concept in frameworks like React that helps optimize performance.

How VDOM improves performance in frameworks

Instead of directly manipulating the real DOM, React first makes changes to the VDOM. When the state of a component updates, React creates a new VDOM tree and compares it to the previous one in a process called diffing. It calculates the minimal number of changes needed to sync the real DOM with the new VDOM. Finally, it batches these changes and updates the real DOM only where necessary.

This approach is faster because:

  • Manipulating a JS object (the DOM) in memory is significantly quicker than directly interacting with the browser's DOM.
  • It reduces the number of costly DOM manipulations, as only the changed parts of the UI are updated.

4.4. React Hooks

React hooks are functions that allow "hooking into" React state and lifecycle features from functional components. They enable the use of state and other React features in functional components, which previously were only available in class components.

  • useState(): the useState() hook allows functional components to manage and update state. It is fundamental for creating interactive and dynamic user interfaces.

  • useRef(): the useRef() hook allows the creation of a mutable reference object that persists across component re-renders without causing the component to re-render when its value changes.

5. Vue Features:

5.1. Ref Function

In Vue.js, a reactive reference refers to a value that any changes are made to this value automatically trigger updates in the UI. The primary way to create such a reference is using the ref function.

  • ref is used to create a reactive reference to a single value. This value can be a primitive type (like string, number, or boolean) or an object/array.
  • When you create a reactive reference with ref, Vue wraps the value in a special object that allows it to detect changes.
  • To access or modify the actual value held by a ref, you must use the .value property (username.value = newValue).

5.2. v-model Directive

The v-model directive in Vue.js is a fundamental feature that enables two-way data binding. It simplifies the synchronization of data between a component's state and form input elements.
For example, when it comes to two-way data binding, v-model automatically handles both updating the UI when the data changes and updating the data when the UI element like an input field is modified.

5.3. defineEmits()

In Vue 3, defineEmits() is a compiler macro used to declare the custom events that a component can emit (the mechanism by which a child component sends a custom event and optionally data to its parent component). It serves as a way to explicitly define the interface for a component's outgoing communication, making it clearer what events a parent component can listen for.

How emit and defineEmits() works

  • When you call emit('event-name'), it triggers the event-name event.
  • The parent component listens for this event (e.g., @event-name="passwordWasSet = true") and can react, such as showing a success message or changing the UI state.

5.4. computed Property

In Vue.js, computed properties play a crucial role in password validation by providing a reactive, efficient way to derive validation states or messages based on other reactive data, such as the password input itself.

How computed works in password validation

  • Deriving Validation Status: you define a computed property that returns a boolean indicating whether the password meets certain criteria (e.g., isPasswordValid, passwordMatch).
import { defineComponent } from 'vue';

export default defineComponent({
  data() {
    return {
      password: '' as string,
      passwordConfirm: '' as string
    };
  },
  computed: {
    passwordMatch(): boolean {
      return this.password === this.passwordConfirm && this.password.length > 0;
    },
    isPasswordStrong(): boolean {
      // Example password strength rule:
      return this.password.length >= 8 && /[A-Z]/.test(this.password);
    }
  }
});
Enter fullscreen mode Exit fullscreen mode

5.5. v-if and v-for

  • v-if: Conditionally renders an element or block. If the condition is true, the element or block is rendered to the DOM; if false, it is removed. This is useful for showing or hiding UI parts based on states (like error messages).

Conjunction with v-else-if and v-else

It can be used in conjunction with v-else-if and v-else to create conditional blocks similar to if/else if/else statements in programming.

<p v-if="isVisible">This paragraph is conditionally rendered.</p>
<p v-else-if="isSecondary">This is a secondary condition.</p>
<p v-else>This is the fallback.</p>
Enter fullscreen mode Exit fullscreen mode
  • v-for: Renders a list of elements by iterating over an array or object. For each item, it creates a new DOM. This is useful for displaying dynamic lists such as password criteria or error messages.

Key attribute

When using v-for, it is recommended to provide a unique key attribute to each iterated element for efficient list updates.

<ul>
  <li v-for="item in items" :key="item.id">
    {{ item.name }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

5.6. aria-invalid Attribute

aria-invalid is an ARIA (Accessible Rich Internet Applications) attribute used to indicate that the entered value is invalid.

How the aria-invalid attribute works

  • If aria-invalid="true" is present on an input, screen readers will announce that the field is invalid, helping users understand which fields require correction.
  • If omitted or set to false, the field is considered valid.
<label for="email">Email:</label>
<input type="email" id="email" aria-invalid="true">
<span id="email-error-message">Please enter a valid email address.</span>
Enter fullscreen mode Exit fullscreen mode

6. Recommended Resource:

With refreshing my frontend domain knowledge at this time, I came across a really convenient resource called GreatFrontEnd. I highly recommend it not only for those who are preparing for technical interviews but also for anyone just starting their frontend journey, as it's a well-structured guide that highlights the essential features and concepts to before stepping into a professional role.

Conclusion

Mastering the fundamentals of JavaScript, TypeScript, React, and Vue gives you the confidence to tackle both interviews and real-world projects. From understanding async code to handling props, refs, and computed values, these core skills are the backbone of modern frontend engineering. Keep practicing, stay curious, and you’ll keep leveling up as a developer.

Top comments (0)