Front End Developer Interview Questions For 5 Years Of Experience

Design patterns in JavaScript are reusable solutions to common software design problems. They provide guidelines and best practices for structuring and organizing code, improving code quality, maintainability, and reusability. Here are some commonly used design patterns in JavaScript: 1. Module Pattern: Encapsulates related functions and variables into a single module, providing a way to create private and public members. It promotes encapsulation and helps avoid global namespace pollution.

var CounterModule = (function() {
  var count = 0;

  return {
    increment: function() {
       count++;
     },
    getCount: function() {
        return count;
   }
  };
})();

CounterModule.increment(); 
CounterModule.increment(); 
CounterModule.getCount();     // Output: 2
CounterModule.count;            //Ouput : 'undefined' as it is a private variable

2. Singleton Pattern: Restricts the instantiation of a class to a single object. It ensures that only one instance of a class is created and provides a global access point to that instance.


var Singleton = (function() {
  var instance;

  function createInstance() {
    var object = new Object("I am the instance");
    return object;
  }

  return {
    getInstance: function() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

var instance1 = Singleton.getInstance();
var instance2 = Singleton.getInstance();

console.log(instance1 === instance2); // Output: true

3. Factory Pattern: Provides an interface for creating objects but allows subclasses or derived classes to decide which class to instantiate. It abstracts the process of object creation and provides flexibility in object creation logic.


function ShapeFactory() {}

ShapeFactory.prototype.createShape = function(type) {
  switch (type) {
    case 'circle':
      return new Circle();
    case 'rectangle':
      return new Rectangle();
    case 'triangle':
      return new Triangle();
    default:
      throw new Error('Invalid shape type');
  }
};

function Circle() {
  this.type = 'circle';
}

function Rectangle() {
  this.type = 'rectangle';
}

function Triangle() {
  this.type = 'triangle';
}

var factory = new ShapeFactory();
var circle = factory.createShape('circle');
var rectangle = factory.createShape('rectangle');
var triangle = factory.createShape('triangle');

console.log(circle.type);     // Output: circle
console.log(rectangle.type);  // Output: rectangle
console.log(triangle.type);   // Output: triangle

4. Observer Pattern: Establishes a one-to-many relationship between objects, where changes in one object (subject) are automatically reflected in other objects (observers). It enables loose coupling between objects and supports event-driven architectures.


function Subject() {
  this.observers = [];
}

Subject.prototype.addObserver = function(observer) {
  this.observers.push(observer);
};

Subject.prototype.removeObserver = function(observer) {
  var index = this.observers.indexOf(observer);
  if (index !== -1) {
    this.observers.splice(index, 1);
  }
};

Subject.prototype.notifyObservers = function(data) {
  this.observers.forEach(function(observer) {
    observer.update(data);
  });
};

function Observer(name) {
  this.name = name;
}

Observer.prototype.update = function(data) {
  console.log(this.name + ' received data: ' + data);
};

var subject = new Subject();
var observer1 = new Observer('Observer 1');
var observer2 = new Observer('Observer 2');

subject.addObserver(observer1);
subject.addObserver(observer2);

subject.notifyObservers('Hello');  // Output: Observer 1 received data: Hello
                                   //         Observer 2 received data: Hello

These are just a few examples of design patterns in JavaScript. Each pattern has its own purpose and solves specific design problems. It's important to understand their concepts and principles to effectively apply them to different software development scenarios.
Conditional breakpoints can be very useful when debugging JavaScript code, as they allow you to pause execution only when certain conditions are met. Here's how to apply conditional breakpoints in the Chrome browser debugging tool: Open the Chrome DevTools by pressing F12 or right-clicking on a web page and selecting "Inspect". 1) Navigate to the "Sources" tab in the DevTools. 2) Find the JavaScript file that you want to debug in the file tree on the left-hand side. 3) Set a regular breakpoint by clicking on the line number where you want to pause execution. 4) Right-click on the breakpoint and select "Edit breakpoint" from the context menu. 5) In the breakpoint editor, enter the condition that you want to use to trigger the breakpoint. For example, you might enter a variable name and a value to pause execution only when the variable has a specific value. 6) Click "Save" to apply the conditional breakpoint. Now, when the code reaches the line with the conditional breakpoint, it will only pause execution if the condition is true. This can save you time and help you quickly identify issues in your code.
Web Workers are a browser feature that allows you to run JavaScript code in the background, separate from the main browser thread. They enable concurrent execution and help prevent blocking the user interface during computationally intensive or time-consuming tasks. Here are some key points about web workers: 1. Background Execution: Web Workers allow you to run scripts in the background without blocking the main thread. This keeps the user interface responsive and improves overall performance. 2. Separate Thread: Web Workers run in a separate thread from the main JavaScript thread, often referred to as the "worker thread." This thread is isolated and doesn't share the same memory space as the main thread. 3. Communication: Web Workers communicate with the main thread using messaging. They can receive messages from the main thread and post messages back to it. This messaging system allows data exchange and coordination between the worker and the main thread. 4. Limited Scope: Web Workers have limited access to browser APIs and the DOM. They can't directly manipulate the DOM or access certain objects and methods available in the main thread. This limitation helps maintain security and prevents worker threads from interfering with the user interface. 5. Types of Web Workers: There are two types of web workers: dedicated workers and shared workers. Dedicated workers are tied to a specific script and can communicate only with the script that created them. Shared workers can be accessed by multiple scripts or web pages running on the same origin, allowing them to share data and communicate with multiple sources. Web Workers are useful for various tasks such as heavy computations, parsing large datasets, performing complex algorithms, and offloading non-UI tasks. They can help improve the overall responsiveness and performance of web applications by distributing the workload across multiple threads. Here's a simple example of using a web worker:

// main.js (main thread)
const worker = new Worker('worker.js');

worker.onmessage = function(event) {
  console.log('Message from web worker:', event.data);
};

worker.postMessage('Hello from main thread!');


// worker.js (worker thread)
self.onmessage = function(event) {
  console.log('Message from main thread:', event.data);
  self.postMessage('Hello from web worker!');
};

In this example, the main thread creates a web worker using the `Worker` constructor, specifying the script file (`worker.js`). The main thread sends a message to the web worker using `worker.postMessage()`. The web worker receives the message in its `onmessage` event handler, logs it, and sends a response back to the main thread using `self.postMessage()`. The main thread receives the response in its `onmessage` event handler and logs it. Web Workers are supported in modern browsers and provide a powerful tool for performing background tasks, improving performance, and enhancing the user experience of web applications.
Accessibility is an essential aspect of web development, ensuring that websites and applications are usable by people with disabilities. Here are some important points related to accessibility: 1. Semantic HTML: Use appropriate HTML tags to convey the structure and meaning of the content. Use headings (`<h1>` to `<h6>`) to organize content, `<p>` for paragraphs, `<nav>` for navigation sections, `<button>` for interactive buttons, etc. This helps screen readers and assistive technologies understand the content and provide a better experience for users. 2. Keyboard Accessibility: Ensure that all functionality can be accessed and operated using a keyboard alone. This is crucial for people with motor disabilities who rely on keyboard navigation. Make sure focus is properly managed and visible, and elements such as buttons, links, and form inputs are keyboard accessible and provide appropriate feedback. 3. Alt Text for Images: Provide descriptive alternative text (`alt` attribute) for images. This allows screen readers to describe the content of images to visually impaired users. Use concise and meaningful descriptions that convey the purpose or information conveyed by the image. 4. Contrast and Color: Use sufficient contrast between text and background colors to ensure readability. Low contrast can make it difficult for people with visual impairments or color blindness to read content. Consider using tools to check contrast ratios and ensure compliance with accessibility standards. 5. Forms and Labels: Use proper form elements and labels to provide clear instructions and associations. Associate labels with form inputs using the `for` attribute or by wrapping the input within the label element. This helps screen readers understand the purpose of form inputs and improves usability for users with visual impairments. 6. Focus Indicators: Ensure that focus indicators are clearly visible and distinguishable. When users navigate through a page using the keyboard, it's important to provide a visual indication of the focused element. This helps users with disabilities understand their location within the page and improves overall navigation. 7. ARIA Roles and Attributes: Use ARIA (Accessible Rich Internet Applications) roles and attributes to enhance the accessibility of complex or custom UI components. ARIA attributes provide additional information to assistive technologies, helping them understand and navigate interactive elements like menus, tabs, and modals. 8. Responsive and Mobile Accessibility: Ensure that your website is responsive and works well on different devices and screen sizes. Consider the needs of users with disabilities who may access your site using mobile devices or assistive technologies. Test your site's accessibility on mobile devices and use media queries to adapt the layout and design. 9. Testing and Auditing: Regularly test and audit your website for accessibility. Use automated accessibility testing tools to identify common issues, and perform manual testing to understand the experience from the perspective of users with disabilities. Incorporate accessibility into your development process to catch and address issues early on. 10. Continuous Learning: Stay updated with accessibility guidelines and best practices. Accessibility standards and techniques evolve, so it's important to continuously learn and improve your understanding of accessibility to create inclusive and usable experiences for all users. These points highlight some important considerations for creating accessible websites and applications. By following accessibility best practices, you can ensure that your content is available and usable by a wider range of users, regardless of their abilities or disabilities. The WCAG 2.0 is organized in three different levels: Level A: the most basic Web accessibility features; Level AA: the most common barriers for disabled people; Level AAA: the highest level of accessibility. Even level A is just the beginning, and the level AA embraced on large companies’ websites, the level AAA is the one to which is hoping that someday all the Web products will go. For reaching those, it’s very important to have empathy for your users, they need to have excellent experiences on the Web, too.
Here's an explanation of Shadow DOM in JavaScript 1. Shadow DOM: Shadow DOM is a web standard that allows for encapsulation of DOM elements within a host element. It provides a way to create a scoped subtree of DOM elements with its own styling and behavior. The encapsulated elements are isolated from the rest of the document, preventing styles and structure from leaking out or being affected by the surrounding page. Example: Let's say we want to create a custom button component that has its own styles and behavior. We can use the Shadow DOM to encapsulate the button's internal implementation.

// Create a custom button element
class CustomButton extends HTMLElement {
  constructor() {
    super();
    
    // Create a shadow root
    const shadow = this.attachShadow({ mode: 'open' });

    // Create a button element
    const button = document.createElement('button');
    button.textContent = 'Click me';
    
    // Add styles to the button
    const styles = document.createElement('style');
    styles.textContent = `
      button {
        background-color: #e0e0e0;
        color: #333;
        padding: 8px 16px;
        border: none;
        border-radius: 4px;
        cursor: pointer;
      }
      
      button:hover {
        background-color: #333;
        color: #fff;
      }
    `;

    // Append the button and styles to the shadow root
    shadow.appendChild(styles);
    shadow.appendChild(button);
  }
}

// Define the custom element
customElements.define('custom-button', CustomButton);

Now, when you use the `<custom-button>` element in your HTML, the internal structure and styles defined within the Shadow DOM will be encapsulated and isolated from the surrounding page.

 <!DOCTYPE html> <html> 
 <head> 
 <title>
   Shadow DOM Example
 </title>
 </head>
 <body>
 <h1>
    My Web Page
 </h1>
 <!-- Custom button element with encapsulated styles -->
 <custom-button></custom-button>
 <script src="custom-button.js"></script>
 </body>
 </html>

Please checkout the detailed explaination here
In Angular, which is a popular JavaScript framework for building web applications, several design patterns are commonly used to structure and organize code. These design patterns help developers create maintainable, scalable, and modular applications. Here are some of the design patterns frequently utilized in Angular: 1. Singleton Pattern: Angular services are often implemented using the Singleton pattern. A service is instantiated once and shared across multiple components, allowing them to communicate and share data. To implement the Singleton pattern in Angular, you can follow these steps: a. Create a service using the Angular CLI:

ng generate service MySingletonService

b. There are two ways to create a single service in angular that is by using - -> providedIn property -> NgModule providers arrays c. Open the generated service file (`my-singleton-service.service.ts`) and modify it as follows:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class MySingletonService {
  // Your service implementation goes here
}

d. The `providedIn: 'root'` property in the `@Injectable` decorator is key to implementing the Singleton pattern in Angular. This tells Angular to provide the service at the root level, making it accessible throughout the application. e. You can now use the `MySingletonService` in your components by injecting it into their constructors:

import { Component } from '@angular/core';
import { MySingletonService } from './my-singleton-service.service';

@Component({
  selector: 'app-my-component',
  template: '...',
})
export class MyComponent {
  constructor(private mySingletonService: MySingletonService) {
    // Access the shared service instance here
  }
}

By injecting `MySingletonService` into multiple components, you will be accessing the same instance of the service across the application, ensuring data consistency and sharing. It's important to note that Angular itself manages the lifecycle of the singleton service. It creates and maintains a single instance of the service and shares it among components that request it. In the case of NgModule providers array, a singleton service is created by passing the service as a value to the providers array and if the NgModule is root app module then the service will be available throughout the application as a singleton service.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { MySingletonService } from './my-singleton-service.service';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  providers: [MySingletonService], // Add the service here
  bootstrap: [AppComponent]
})
export class AppModule { }

That's how you can implement the Singleton pattern in Angular using a service. This allows you to share data, maintain state, and provide centralized functionality throughout your application. 2. Dependency Injection (DI) Pattern: Angular utilizes the DI pattern to manage the dependencies between components and services. With DI, the required dependencies are provided to a component or service through constructor injection or property injection, promoting loose coupling and testability.

// Component using DI
constructor(private productService: ProductService) {
  // Use the productService
}

3. Observer Pattern: Angular leverages the Observer pattern through the EventEmitter class and the RxJS library. Components can emit events using EventEmitters, and other components can subscribe to these events to react accordingly.

// Component emitting an event
@Output() productSelected = new EventEmitter();

selectProduct(product: Product) {
  this.productSelected.emit(product);
}

// Component subscribing to an event


4. Strategy Pattern: The Strategy pattern enables you to dynamically select and switch between different strategies at runtime based on specific conditions or requirements. By encapsulating these behaviors in separate classes, components can switch between strategies based on specific conditions. Here's an example of implementing the Strategy pattern in Angular: a. Define an interface that represents the common behavior of the strategies. Let's assume we have a payment processing scenario:

// payment-strategy.interface.ts
export interface PaymentStrategy {
  processPayment(amount: number): void;
}

b. Implement multiple strategies by creating separate classes that implement the `PaymentStrategy` interface. Each class will provide its own implementation of the `processPayment` method:

// credit-card-strategy.ts
export class CreditCardStrategy implements PaymentStrategy {
  processPayment(amount: number): void {
    console.log(`Processing credit card payment of $${amount}`);
    // Perform credit card payment processing logic here
  }
}

// paypal-strategy.ts
export class PaypalStrategy implements PaymentStrategy {
  processPayment(amount: number): void {
    console.log(`Processing PayPal payment of $${amount}`);
    // Perform PayPal payment processing logic here
  }
}

c. Create a context class that will use the strategies and provide a method to set the active strategy:

// payment-context.ts
import { PaymentStrategy } from './payment-strategy.interface';

export class PaymentContext {
  private strategy: PaymentStrategy;

  setStrategy(strategy: PaymentStrategy): void {
    this.strategy = strategy;
  }

  processPayment(amount: number): void {
    this.strategy.processPayment(amount);
  }
}

d. Now, you can utilize the strategies in your Angular components or services. For example:

import { Component } from '@angular/core';
import { PaymentContext } from './payment-context';
import { CreditCardStrategy } from './credit-card-strategy';
import { PaypalStrategy } from './paypal-strategy';

@Component({
  selector: 'app-payment-component',
  template: '...',
})
export class PaymentComponent {
  constructor(private paymentContext: PaymentContext) {}

  processCreditCardPayment(amount: number): void {
    this.paymentContext.setStrategy(new CreditCardStrategy());
    this.paymentContext.processPayment(amount);
  }

  processPaypalPayment(amount: number): void {
    this.paymentContext.setStrategy(new PaypalStrategy());
    this.paymentContext.processPayment(amount);
  }
}

e. In this example, the `PaymentComponent` uses the `PaymentContext` to switch between different payment strategies (`CreditCardStrategy` and `PaypalStrategy`) based on user actions or conditions. By setting the active strategy through `setStrategy`, you can dynamically change the behavior of the payment processing logic in `processPayment`. This implementation allows for easy extensibility, as you can add new strategies by implementing the `PaymentStrategy` interface and use them interchangeably within the `PaymentComponent` or any other component that requires payment processing functionality. The Strategy pattern provides flexibility and maintainability by separating the implementation of different algorithms or behaviors from the client code, allowing you to change or extend strategies without modifying existing code. 5. Decorator Pattern: Angular decorators, such as @Component and @Injectable, are based on the Decorator pattern. Decorators provide a way to enhance or modify the behavior of classes or class members without directly modifying the underlying code. a. Create a base component that represents the core functionality:

import { Component } from '@angular/core';

@Component({
  selector: 'app-base-component',
  template: 'Base Component',
})
export class BaseComponent {}

b. Create a decorator component that extends the base component:

import { Component, ViewChild } from '@angular/core';
import { BaseComponent } from './base-component';

@Component({
  selector: 'app-decorator',
  template: `
    <div>
      <p>This is the decorator component</p>
      <ng-content></ng-content>
    </div>
  `,
})
export class DecoratorComponent extends BaseComponent {}

In this example, the `DecoratorComponent` is a child component that extends the functionality of the `BaseComponent`. It wraps the `BaseComponent` within itself and adds extra content using `<ng-content>`. This allows you to inject additional behavior or template content around the base component. c. Use the decorator component in your application:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <app-decorator>
      <app-base-component></app-base-component>
    </app-decorator>
  `,
})
export class AppComponent {}

In the `AppComponent` template, the `BaseComponent` is wrapped within the `DecoratorComponent` using its selector `<app-decorator>`. You can inject other components, templates, or HTML content within the `DecoratorComponent` to extend or modify the behavior of the `BaseComponent`. By using the Decorator pattern in Angular, you can dynamically extend or modify the functionality of existing components by wrapping them within decorator components. This approach provides flexibility, code reusability, and maintainability, as you can reuse the base components while adding specific behavior or content as needed. 6. Facade Pattern:The Facade pattern is a structural design pattern that provides a simplified interface to a complex subsystem, making it easier to use and understand. In Angular, you can apply the Facade pattern to create a simplified API or service that encapsulates the complexity of interacting with multiple components, services, or modules. Here's an example of implementing the Facade pattern in Angular: a. Identify a complex subsystem or set of related components/services that you want to simplify for client usage. b. Create a Facade service that encapsulates the interactions with the complex subsystem. The Facade service will provide a simplified interface for clients to access the subsystem's functionality.

import { Injectable } from '@angular/core';
import { ComplexServiceA } from './complex-service-a';
import { ComplexServiceB } from './complex-service-b';

@Injectable()
export class FacadeService {
  constructor(private serviceA: ComplexServiceA, private serviceB: ComplexServiceB) {}

  // Provide simplified methods that internally call the appropriate complex subsystem methods
  performOperation(): void {
    this.serviceA.complexOperationA();
    this.serviceB.complexOperationB();
  }
}

c. Implement the complex subsystem components/services that the Facade service interacts with. These components/services handle the actual complex logic.

@Injectable()
export class ComplexServiceA {
  complexOperationA(): void {
    // Complex logic of service A
    console.log('Performing complex operation A');
  }
}

@Injectable()
export class ComplexServiceB {
  complexOperationB(): void {
    // Complex logic of service B
    console.log('Performing complex operation B');
  }
}

d. Use the Facade service in your components to simplify the usage of the complex subsystem:

import { Component } from '@angular/core';
import { FacadeService } from './facade.service';

@Component({
  selector: 'app-client-component',
  template: '...',
})
export class ClientComponent {
  constructor(private facadeService: FacadeService) {}

  performFacadeOperation(): void {
    this.facadeService.performOperation();
  }
}

e. In this example, the `ClientComponent` utilizes the `FacadeService` to perform complex operations without needing to interact directly with the complex subsystem (`ComplexServiceA` and `ComplexServiceB`). The `FacadeService` encapsulates the complexity and provides a simplified interface for the client component to interact with. By using the Facade pattern in Angular, you can simplify the usage of complex subsystems, hide their implementation details, and provide a straightforward and easy-to-use interface for clients. This promotes code maintainability, readability, and modularity by abstracting the complexity of interacting with multiple components or services behind a single facade. 7. Composite Pattern: The Composite Design Pattern is a structual design pattern that is used to compose objects into a tree-like structure. Components can be composed of other components, forming a tree-like structure. This pattern enables the creation of reusable and hierarchical UI components. In Angular, you can apply the Composite pattern to represent hierarchical relationships between components or services. Here's an example of implementing the Composite pattern in Angular: a. Create an abstract class or interface that represents the common behavior for both individual objects and groups:

// component.interface.ts
export interface ComponentInterface {
  operation(): void;
}

b. Implement the abstract class or interface for individual objects:

// leaf.component.ts
import { ComponentInterface } from './component.interface';

export class LeafComponent implements ComponentInterface {
  operation(): void {
    console.log('Performing operation on a leaf component.');
  }
}

c. Implement the abstract class or interface for the composite object, which can contain both individual objects and other composite objects:

// composite.component.ts
import { ComponentInterface } from './component.interface';

export class CompositeComponent implements ComponentInterface {
  private children: Component[] = [];

  add(component: ComponentInterface): void {
    this.children.push(component);
  }

  remove(component: ComponentInterface): void {
    const index = this.children.indexOf(component);
    if (index > -1) {
      this.children.splice(index, 1);
    }
  }

  operation(): void {
    console.log('Performing operation on the composite component.');
    for (const child of this.children) {
      child.operation();
    }
  }
}

d. Use the composite object to create a tree-like structure of components:

import { ComponentInterface } from './component.interface';
import { LeafComponent } from './leaf.component';
import { CompositeComponent } from './composite.component';

// Create leaf components
const leaf1: ComponentInterface = new LeafComponent();
const leaf2: ComponentInterface = new LeafComponent();

// Create composite component
const composite: ComponentInterface = new CompositeComponent();
composite.add(leaf1);
composite.add(leaf2);

// Create another composite component
const composite2: ComponentInterface = new CompositeComponent();
composite2.add(composite);
composite2.add(leaf1);

// Perform operation on the composite structure
composite2.operation();

e. In this example, we create a tree-like structure using the Composite pattern. The `CompositeComponent` can contain both individual `LeafComponent` objects and other `CompositeComponent` objects. Calling the `operation()` method on the top-level `CompositeComponent` will recursively invoke the operation on all its children, whether they are leaf components or other composite components. By using the Composite pattern in Angular, you can represent complex hierarchical relationships between components or services in a uniform manner. It allows you to treat individual objects and groups of objects in a consistent way, simplifying the code and enabling recursive operations on the composite structure. 8.Factory Pattern: The Factory pattern is a creational design pattern that provides an interface for creating objects without specifying the exact class of the object that will be created. In Angular, you can apply the Factory pattern to encapsulate object creation logic and provide a centralized place for creating instances of different classes. Here's an example of implementing the Factory pattern in Angular: a. Define an abstract class or interface that represents the common behavior of the objects you want to create:
// product.interface.ts
export interface Product {
  operation(): void;
}

b. Implement multiple classes that conform to the `Product` interface:

// product-a.ts
export class ProductA implements Product {
  operation(): void {
    console.log('Product A operation.');
  }
}

// product-b.ts
export class ProductB implements Product {
  operation(): void {
    console.log('Product B operation.');
  }
}

c. Create a factory class that encapsulates the object creation logic:

// product-factory.ts
import { Product } from './product.interface';
import { ProductA } from './product-a';
import { ProductB } from './product-b';

export class ProductFactory {
  createProduct(type: string): Product {
    if (type === 'A') {
      return new ProductA();
    } else if (type === 'B') {
      return new ProductB();
    }

    throw new Error('Invalid product type');
  }
}

d. Use the factory class to create instances of the desired products:

import { Component } from '@angular/core';
import { ProductFactory } from './product-factory';
import { Product } from './product.interface';

@Component({
  selector: 'app-example',
  template: '...',
})
export class ExampleComponent {
  constructor(private productFactory: ProductFactory) {}

  createProduct(type: string): void {
    const product: Product = this.productFactory.createProduct(type);
    product.operation();
  }
}

e. In this example, the `ExampleComponent` uses the `ProductFactory` to create instances of different products based on the provided type. By calling the `createProduct` method with the desired type ('A' or 'B'), it receives an instance of the corresponding product class and can invoke its `operation()` method. Using the Factory pattern in Angular provides a centralized place for creating objects and decouples the client code from the concrete classes. It allows for flexible object creation and enables easy extensibility by adding new product classes and updating the factory logic accordingly. These are some of the design patterns commonly used in Angular. However, it's worth noting that Angular itself follows the MVC (Model-View-Controller) architectural pattern, where components serve as the controllers, templates represent views, and services act as models.
Decorators are a design pattern that is used to separate modification or decoration of a class without modifying the original source code. In Angular, decorators are functions that allow a service, directive or filter to be modified prior to its usage. Create decorator


function log(target,name,descriptor) {
  const original=descriptor.value;
  descriptor.value=function(...args) {
    console.log('this function is hacked')
    const result=original.apply(this,args)
    console.log("the result of the function is ", result);
    return result;
  }
  original();
  return descriptor;
}

Usage of decorator


 @log
  sum(a,b) {
    return a+b;
  }
//function overridden by decorator called
sum(2,3)

//output will be
this function is hacked
 the result of the function is  5

Using order property as shown in below code :- HTML:-

<div id="main">
  <div style="background-color:coral;" id="myRedDIV"></div>
  <div style="background-color:lightblue;" id="myBlueDIV"></div>
  <div style="background-color:lightgreen;" id="myGreenDIV"></div>
  <div style="background-color:pink;" id="myPinkDIV"></div>
</div>

CSS:-

#main {
  width: 400px;
  height: 150px;
  border: 1px solid #c3c3c3;
  display: -webkit-flex; /* Safari */
  display: flex;
}


#main div {
  width: 70px;
  height: 70px;
}


/* Safari 6.1+ */
div#myRedDIV   {-webkit-order: 2;}
div#myBlueDIV  {-webkit-order: 4;}
div#myGreenDIV {-webkit-order: 1;}
div#myPinkDIV  {-webkit-order: 3;}


/* Standard syntax */
div#myRedDIV   {order: 2;}
div#myBlueDIV  {order: 4;}
div#myGreenDIV {order: 1;}
div#myPinkDIV  {order: 3;}

The HTML <map> tag defines an image map. An image map is an image with clickable areas. The areas are defined with one or more <area> tags. HTML:-

<img src="workplace.jpg" alt="Workplace" usemap="#workmap" width="400" height="379">

<map name="workmap">
  <area shape="rect" coords="34,44,270,350" alt="Computer" href="computer.htm">
  <area shape="rect" coords="290,172,333,250" alt="Phone" href="phone.htm">
  <area shape="circle" coords="337,300,44" alt="Cup of coffee" href="coffee.htm">
</map>

For more information click here