splice vs slice in javascript

 'splice()' and 'slice()' are two array techniques in JavaScript that are often confused with each other. In order to resolve these ambiguities, we will compare the two methods below step by step.

splice vs slice javascript


1. Creating a Slice: The Simple Version

Purpose

Evaluates only a small part of an array without changing it.

Usage

array.slice(startIndex, endIndex);

Main Points

  • Produces a new array consisting of the elements from startIndex to endIndex (not inclusive).
  • Changes made to the original array are not visible.
  • If indexes are negative, they count from the end.
  • If no arguments are given, then array.slice() makes a shallow copy of the entire array.

Example

const fruits = ['apple', 'banana', 'cherry', 'date'];

const sliced = fruits.slice(1, 3);

console.log(sliced); // ['banana', 'cherry']

console.log(fruits); // ['apple', 'banana', 'cherry', 'date'] (that's how it remained)

2. splice(): Add/Remove Elements from an Array

Purpose

Alters the original array, inserts or deletes elements.

Syntax

array.splice(startIndex, deleteCount, item1, item2,...);

Key Points

  • Changes the original array.
  • Returns an array followed by the removed elements (if any).
  • Deleting, adding or changing elements on the spot are all possible.

Examples

a. Deleting Elements

const numbers = [1, 2, 3, 4, 5];

const removed = numbers.splice(1, 2); // Start removing from position 1 and remove 2 from that

console.log(removed); // [2, 3]

console.log(numbers); // [1, 4, 5]

b. Adding Elements

const colors = ['red', 'blue'];

colors.splice(1, 0, 'green'); // Add 'green' after index 1 without deleting anything

console.log(colors); // ['red', 'green', 'blue']

c. Replacing Elements

const letters = ['a', 'b', 'c'];

letters.splice(1, 1, 'x'); // Replace 'b' with 'x' at index 1

console.log(letters); // ['a', 'x', 'c']

3. The Key Differences

Featureslice()splice()
Mutates OriginalNoYes
Return ValueNew array of extracted elementsArray of removed elements (if any)
Parameters(start, end)(start, deleteCount, items...)
Use CaseCopy a piece of an arrayAdd/remove elements in place

  • Slice Use it when you need to take a part from the array out without changing the original.
  • Example: Generate a copy of an array:
  • const copy = arr.slice();
  • Splice Use it when you need to remove, add, or adjust an array.
  • Example: Update a list dynamically, such as editing a to-do list.

5. Pitfalls of Using These Two Methods

Mixed Parameters Puzzle

  • Slice (1, 3) obtains elements from indices 1 and 2 (excluding index 3).
  • Splice (1, 3) starts at index 1 and removes three elements.

Splice's Mutability

  • Splice() changes the original array, so always make sure you don't need to preserve the original data before using it.

Summary

  • Slice: copy parts of an array without changing the original.
  • Splice: can edit an array directly, deleting, introducing or replacing parts.

5 Simple Ways to Copy an Array in JavaScript

5 Simple Ways to Copy an Array in JavaScript

In JavaScript, there are 5 simple ways to copy an array to another array. Here are some examples and explanations.

5 Simple Ways to Copy an Array in JavaScript


1. Using the Spread Operator (...)

The newest and easiest way (ES6 and above):

const original = [1, 2, 3];
const copy = [...original];
console.log(copy); // [1, 2, 3]

2. Using slice()

A traditional method for making a shallow copy:

const original = ['a', 'b', 'c'];
const copy = original.slice();
console.log(copy); // ['a', 'b', 'c']

3. Using Array.from()

Turns an iterator (like an array) into a new array:

const original = [10, 20, 30];
const copy = Array.from(original);
console.log(copy); // [10, 20, 30]

4. Using concat()

Copies the original array by adding an empty array:

const original = [true, false, true];
const copy = original.concat();
console.log(copy); // [true, false, true]

5. Using map()

Iterates through and returns every item (rare but feasible):

const original = [{ name: 'Alice' }, { name: 'Bob' }];
const copy = original.map(item => item);
console.log(copy); // [{ name: 'Alice' }, { name: 'Bob' }]

Shallow Copy vs. Deep Copy

Shallow Copy

The methods above copy primitive values (numbers, strings), but reference objects (arrays/objects inside an array) still refer to the same memory location as the original.

const original = [{ x: 1 }];
const copy = [...original];
copy[0].x = 99; 
console.log(original[0].x); // 99 😱

Deep Copy

For nested arrays/objects, use:

const deepCopy = JSON.parse(JSON.stringify(original));

Note: This does not work for Date objects, functions, or circular references.

Which Method Should You Use?

Use Spread Operator ([...arr]) or Array.from() → Suitable for most cases.
Need browser support for older code? → Use slice()

.
Need a deep copy? → Use JSON.parse(JSON.stringify(arr)) (with restrictions) or a library like _.cloneDeep() from Lodash.

Common Mistake

🚨 Do not assign arrays directly! This only creates a reference, not a copy.

const original = [1, 2, 3];
const badCopy = original; // Both point to the same array!
badCopy.push(4);
console.log(original); // [1, 2, 3, 4] 😱

Let me know if you need any further improvements! 😊

Javascript versions list

ESMAScript Versions and Features

JavaScript, a programming language that defines the Web, has evolved significantly since its birth in 1995. Starting as a simple scripting tool, it has grown into a diverse and powerful language.

We will use ECMAScript (ES) standards to trace its evolution. This blog post provides an overview of JavaScript versions, their history, and key characteristics, creating a context for modern web development.

1. Introduction: JavaScript and ECMAScript

JavaScript was created by Brendan Eich in 1995 for Netscape Navigator. Later, ECMA International, a standards organization, formalized it under the ECMAScript (ES) specification. While commonly referred to as "JavaScript," ECMAScript represents the standardized version of the language.

Major Milestones:

ESMAScript Versions and Features  javascript versions


2. Early Versions: Laying the Foundation

Key Features:

  • var for variable declaration
  • Primitive types (string, number, boolean, null, undefined)
  • Functions and objects

ES1 (1997)

The first standardized version, ECMAScript 1, established core syntax, types, and basic functionalities such as loops and conditionals.

Key Features:

  • var for variable declaration
  • Primitive types (string, number, boolean, null, undefined)
  • Functions and objects

ES3 (1999)

A significant step forward, introducing features still in use today.

Key Features:

  • try...catch for error handling
  • Regular expressions
  • switch statements

ES4 (Abandoned)

This version was abandoned due to complexity and controversy over its many new features.


3. ES5 (2009): Modernizing JavaScript

ES5 marked JavaScript's shift into the modern age.

Key Features:

  • Strict Mode: Enforces safer coding practices (e.g., preventing undeclared variables).
  • JSON Support: JSON.parse() and JSON.stringify().
  • Array Methods: forEach(), map(), filter(), reduce().
  • Getters/Setters: Object property accessors.
// ES5 Array Method Example
var numbers = [1, 2, 3];
numbers.forEach(function(num) {
    console.log(num * 2);
});
// Output: 2, 4, 6

4. ES6/ES2015: The Revolution

Released in 2015, ES6 was a game changer. It improved syntax and introduced powerful new abstractions.

Key Features:

  • let and const: Block-scoped variables.
  • Arrow Functions: Concise syntax, lexical this.
  • Classes: Syntactic sugar over prototypes.
  • Promises: Improved asynchronous handling.
  • Modules: import /export syntax.
  • Template Literals: Interpolated strings with ${}.
  • Destructuring: Extracts values from arrays/objects.
// ES6 Arrow Function and Destructuring
const user = { name: 'Alice', age: 30 };
const greet = ({ name }) => `Hello, ${name}!`;
console.log(greet(user)); // "Hello, Alice!"

5. Annual Releases: ES2016 to ES2023

ES2016

  • Array.prototype.includes(): Check if an array contains a value.
  • Exponentiation operator (**): 2 ** 3 = 8.

ES2017

  • Async/Await: Makes asynchronous code look synchronous.
  • Object.values() / Object.entries(): Extract data from objects.
// Async/Await Example
async function fetchData() {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
}

ES2018

  • Spread/Rest for Objects: const clone = {...obj };
  • Promise.finally(): Executes code after promise resolution.

ES2020

  • Optional Chaining: user?.address?.city (runs only if address is not null or undefined).
  • Nullish Coalescing: const value = input ?? 'default'; (checks for null /undefined).

ES2021

  • String.replaceAll(): Replaces all instances of a substring.
  • Logical Assignment Operators: ||=, &&=, ??=.

ES2022

  • Top-Level Await: Use await outside of async functions in modules.
  • Class Fields: Declare properties directly in classes.

ES2023

  • Array.findLast(): Find from last in array.
  • Hashbang Support: Standardized syntax for CLI scripts (#!/usr/bin/env node).

6. The Rise of ES Modules and Tooling

ES6 introduced native modules, replacing older patterns like CommonJS.

// Import/Export Syntax
import { Component } from 'react';
export default function App() {};

Modern Tooling:

  • Babel: Transpile modern JS to older versions for browser compatibility.
  • Webpack/Rollup: Bundle modules for production.
  • TypeScript: Provides static typing for JavaScript.

7. Using Modern JavaScript Today

Most browsers support ES6+ features, but in older environments:

  • Transpilation: Convert modern syntax into older (e.g., Babel).
  • Polyfills: Fill missing methods (e.g., Promise).

8. The Future: ES2024 and Beyond

Proposed Features for ES2024:

  • Records and Tuples: Immutable data structures.
  • Pipeline Operator: value |> function for functional chaining.
  • Decorators: Standardizes meta-programming for classes/methods.

Conclusion: Why JavaScript’s Evolution Matters

The evolution of JavaScript parallels the increasing complexity of the web. Each version, from ES5’s strict mode to the ergonomic improvements of ES2023, enables developers to write cleaner, safer, and more efficient code.

    ng-template & ng container in angular

     In an Angular application, the user interface is the fact: the tags themselves, stored in a template file. Most developers are familiar with both components and directives. However, the ng-template directive is a powerful but often misunderstood tool. This blog will teach you what ng-template is, provide some examples, and show how it lets Angular applications display advanced UI patterns.
    Understanding ng-template and ng-container in Angular

    What is ng-template?

    ng-template is an Angular directive that specifies a template block not to be rendered by the browser by default. Instead, it is treated as a blueprint for making dynamic places: when combined with structural directives such as *ngIf, *ngFor, or your own, one of the above might as well be called a register. Here is a way to save.

    Characteristics

    1. Not Rendered at the Beginning: It's as if everything inside ng-template were dull, waiting for approval.
    2. Collaborates with Structural Directives: Used to mark content which depends on something like a condition you may want to show a larger view of or data that is supposed to not just go away.
    3. Takes Contextual Information: Lets you pass data to templates for dynamic rendering.

    Basic Usage of ng-template

    Example 1: Conditional Rendering with *ngIf and else

    This is a common use case where alternate content is shown when a particular condition isn’t true:

    <div *ngIf="userLoggedIn; else loginPrompt">
      Welcome, {{ username }}!
    </div>
    
    <ng-template #loginPrompt>
      <p>Please log in.</p>
    </ng-template>
    

    Here:

    • The else clause calls the loginPrompt template.
    • The loginPrompt template only gets rendered when userLoggedInis false.

    How It Works:

    Angular converts the *ngIf syntax into:

    <ng-template [ngIf]="userLoggedIn">
      <div>Welcome, {{ username }}!</div>
    </ng-template>
    

    The #loginPrompt is a template reference variable pointing to the ng-template.

    The Role of Structural Directives

    Structural directives (e.g., *ngIf, *ngFor) manipulate the DOM by adding or removing elements. As it turns out, they use ng-template to define the content they manage.

    Example 2: How *ngFor Uses ng-template

    This code:

    <ul>
      <li *ngFor="let item of items; let i = index">{{ i }}: {{ item }}</li>
    </ul>
    

    Turns into this thanks to Angular:

    <ul>
      <ng-template ngFor let-item [ngForOf]="items" let-i="index">
        <li>{{ i }}: {{ item }}</li>
      </ng-template>
    </ul>
    

    The contents of ng-template provide the structure that gets repeated for each item in items .

    Advanced Use Cases

    1. Dynamic Templates with ngTemplateOutlet

    Use ngTemplateOutlet to render a template dynamically, optionally with context data:

    @Component({
      template: `
        <ng-container *ngTemplateOutlet="greetingTemplate; context: { $implicit: 'User' }">
        </ng-container>
    
        <ng-template #greetingTemplate let-message>
          Welcome, {{ message }}!
        </ng-template>
      `
    })
    

    Here:

    • ngTemplateOutlet displays greetingTemplate, together with context information.
    • let-message gets the context's $implicit value.

    2. Custom Structural Directives

    Create reusable directives that leverage ng-template:

    @Directive({
      selector: '[appRepeat]'
    })
    export class RepeatDirective {
      constructor(
        private templateRef: TemplateRef<any>,
        private viewContainer: ViewContainerRef
      ) {}
    
      @Input() set appRepeat(times: number) {
        this.viewContainer.clear();
        for (let i = 0; i < times; i++) {
          this.viewContainer.createEmbeddedView(this.templateRef, { $implicit: i + 1 });
        }
      }
    }
    

    Usage:

    <ul>
      <li *appRepeat="3">Item {{ count }}</li>
    </ul>
    

    Output:

    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </ul>
    
    3. Content Projection with ng-content and Templates
    Pass templates to components as inputs for flexible content projection.
    Parent Component:

    <app-card>
    <ng-template #header>My Custom Header</ng-template>
    <ng-template #body>Body: {{ data }}</ng-template>
    </app-card>
    @Component({
    selector: 'app-card',
    template: `
    <div class="card">
    <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
    <ng-container *ngTemplateOutlet="bodyTemplate; context: { data: cardData }"></ng-container>
    </div>
    `,
    })
    export class CardComponent {
    @ContentChild('header') headerTemplate!: TemplateRef<any>;
    @ContentChild('body') bodyTemplate!: TemplateRef<any>;
    cardData = 'Sample data';
    }

    ng-template vs. ng-container

    Featureng-templateng-container
    RenderingNot rendered by defaultRendered as a lightweight container
    Use CaseDefine reusable template blocksGroup elements without adding extra DOM nodes
    Structural DirectivesRequires a directive to renderCan host structural directives directly
    Best Practices

    Child Component (app-card):
    • Avoid Overuse of Templates: Use ng-template only when necessary to keep the DOM clean.

    • Pass Data Through Context: Use context objects for dynamic template rendering.

    • Combine with ng-container: Use ng-container for grouping structural directives to prevent unnecessary DOM elements.

    What is changedetector and its use in agular

     Throwing Yourself into ChangeDetector in Angular: Sinking Your Doe into Performance

    When traditional web frameworks make the user interface (UI) just one big application that responds to all its own new data, the main job of change detection is to stop this from breaking down. In Angular, this duty is managed by an advanced change detection mechanism.

    The core of this mechanism is ChangeDetectorRef, a powerful tool for optimizing performance and regulating how and when Angular updates the DOM. In this article, we will examine what ChangeDetectorRef can do, how it does it, and how it is used in practice.

    What is Change Detection in Angular?

    Before sinking into ChangeDetectorRef, let’s get an initial understanding of change detection.

    Angular applications are dynamic: data changes over time owing to user interactions, API calls, or via timers. When data changes, Angular needs to update the DOM so that it reflects the new state of affairs. This job of synchronizing the data model with the UI is called change detection.

    Angular’s default change detection strategy observes all components in the application every time an event occurs (e.g., click, HTTP response, or timer tick). While this method ensures accuracy, it can become inefficient as the application size and component tree structure increase since it requires all components to be checked.

    To address this problem, Angular provides help for speeding up certain aspects of the transfer of information, such as the ChangeDetectorRef class.

    What is ChangeDetectorRef?

    ChangeDetectorRef is a class provided by Angular’s @angular/core module. It allows developers to manage a component’s change detection system directly. By using ChangeDetectorRef, you can optimize performance by reducing unnecessary checks or forcing updates when needed.

    Key Methods of ChangeDetectorRef

    Let’s look at the four principal methods of ChangeDetectorRef:

    1. detectChanges()
    • What it does: Triggers change detection immediately for the present component and its children.
    • Use case: After modifying data outside Angular’s awareness (e.g., in a setTimeout or third-party library callback), update the UI.
    import { Component, ChangeDetectorRef } from '@angular/core';
    
    @Component({
      selector: 'app-example',
      template: `{{ data }}`
    })
    export class ExampleComponent {
      data: string;
    
      constructor(private cdr: ChangeDetectorRef) {
        setTimeout(() => {
          this.data = 'Updated!';
          this.cdr.detectChanges(); // Manually trigger update
        }, 1000);
      }
    }
    
    1. markForCheck()
    • What it does: Marks the present component and its ancestors for check during the next change detection cycle. Used with OnPush strategy.
    • Use case: Notify Angular to check a component when its inputs change or internal state is updated.
    @Component({
      selector: 'app-onpush',
      template: `{{ counter }}`,
      changeDetection: ChangeDetectionStrategy.OnPush // Optimize with OnPush
    })
    export class OnPushComponent {
      counter = 0;
    
      constructor(private cdr: ChangeDetectorRef) {}
    
      increment() {
        this.counter++;
        this.cdr.markForCheck(); // Schedule check for next cycle
      }
    }
    
    1. detach() and reattach()
    • What they do:
      • detach(): Automatically disables change detection on the component.
      • reattach(): Re-enables it.
    • Use case: Temporarily cease change detection within performance-critical sections.
    export class DetachExampleComponent {
      constructor(private cdr: ChangeDetectorRef) {
        this.cdr.detach(); // Disable auto-checking
      }
    
      updateData() {
        // Changes here won't reflect on the UI until reattached
        this.cdr.reattach(); // Re-enable checking
        this.cdr.detectChanges();
      }
    }
    

    Use Cases for ChangeDetectorRef

    1. Optimizing Performance with OnPush

    The OnPush change detection strategy reduces checks down to only the present component and its ancestors by carrying out operations only when:

    • Input properties change.
    • A component emits an event (e.g., clicking a button).
    • markForCheck() is called.

    Using ChangeDetectorRef.markForCheck() with OnPush reduces the number of non-essential checks, which improves performance when applications grow large or have complex component structures.

    1. Integrating Third-Party Libraries

    By using non-Angular libraries (e.g., D3.js or jQuery plugins), data changes can occur outside the reach of Angular’s zone. In these cases, you have to use detectChanges() to update the UI.

    ngAfterViewInit() {
      const chart = d3.select(this.elementRef.nativeElement).append('svg')
      //... setup chart
      chart.on('click', () => {
        this.selectedData = newData;
        this.cdr.detectChanges(); // Force UI update
      });
    }
    
    1. Managing Async Operations Outside Angular’s Zone

    By default, Angular performs change detection when async operations (e.g., setTimeout) finish. If you run code outside Angular’s zone (via NgZone.runOutsideAngular), you must use detectChanges() to update.

    constructor(private ngZone: NgZone, private cdr: ChangeDetectorRef) {
      this.ngZone.runOutsideAngular(() => {
        setTimeout(() => {
          this.data = 'Updated outside Angular!';
          this.cdr.detectChanges(); // Manual update
        }, 1000);
      });
    }
    

    Best Practices and Pitfalls

    • Avoid Overusing Manual Detection: Wherever possible, rely on Angular’s default mechanism. Overuse of detectChanges() will complicate debugging.
    • Combine with OnPush: Use markForCheck() to maximize performance gains.
    • Reattach Detached Components: Forgetting to reattach a component can cause the UI to become stale.
    • Unsubscribe from Observables: To prevent memory leaks, always clean up subscriptions.

    Conclusion

    Angular’s ChangeDetectorRef gives developers fine-grained control over change detection, making it a powerful tool for optimizing application performance. Whether you’re refactoring operations with OnPush, integrating third-party libraries, or managing async operations outside Angular’s zone, understanding ChangeDetectorRef is essential.

    By strategically using detectChanges(), markForCheck(), and detach(), you can ensure that your Angular applications perform efficiently.

    And remember: with great power comes great responsibility—use these techniques wisely to maintain code quality and application stability.


    router-outlet and it's purpose

    Understanding <router-outlet> in Angular and Its Purpose

    In Angular, the <router-outlet> directive plays an important role in navigation and showing components dynamically based on the router configuration of the application. Let's see more about its purpose, how it works, and a few advanced use examples.

    Understanding `router-outlet` and Its Purpose in Angular


    What is <router-outlet>?

    <router-outlet> is an Angular built-in directive used as a placeholder for dynamically loaded routed components based on the application's router configuration. It acts as a viewport where Angular inserts the content of the active route.

    Purpose of <router-outlet>

    • Dynamic Component Loading: It allows Angular to render different components based on the URL path.
    • Single Page Application (SPA): It helps build SPAs by loading only those parts of a page that are needed without reloading it entirely.
    • Supports Nested Routing: Multiple <router-outlet> elements can be used to create child routes and complex navigation structures.
    • Smooth Transitions: Enables seamless navigation between views without requiring a page refresh.

    How <router-outlet> Works

    Step 1: Define Routes in app-routing.module.ts

    import { NgModule } from "@angular/core";  
    import { RouterModule, Routes } from "@angular/router";  
    import { HomeComponent } from "./home/home.component";  
    import { AboutComponent } from "./about/about.component";  
    
    const routes: Routes = [  
      { path: "", component: HomeComponent },  
      { path: "about", component: AboutComponent }  
    ];  
    
    @NgModule({  
      imports: [RouterModule.forRoot(routes)]  
    })  
    export class AppRoutingModule { }  
    

    Step 2: Add <router-outlet>to app.component.html

    <nav>  
      <a routerLink="/">Home</a>  
      <a routerLink="/about">About</a>  
    </nav>  
    
    <router-outlet></router-outlet>  
    
    • Clicking on Home (/) will load HomeComponent inside <router-outlet>.
    • Clicking on About (/about) will load AboutComponent dynamically into <router-outlet>.

    Using Multiple <router-outlet> for Nested Routing

    If your application has a three-level navigation structure (Parent → Child → Grandchild), you can use multiple <router-outlet> elements.

    Example: Parent-Child Routing

    const routes: Routes = [  
      {  
        path: 'dashboard', component: DashboardComponent,  
        children: [  
          { path: 'profile', component: ProfileComponent },  
          { path: 'settings', component: SettingsComponent }  
        ]  
      }  
    ];  
    

    dashboard.component.html

    <h2>Dashboard</h2>  
    <a routerLink="profile">Profile</a>  
    <a routerLink="settings">Settings</a>  
    
    <router-outlet></router-outlet> <!-- Child items are mounted here -->
    
    • Enter /dashboard/profile, and DashboardComponent will be shown.
    • ProfileComponent will be displayed inside the <router-outlet> inside DashboardComponent.

    Named <router-outlet>for Multiple Views

    You can use named outlets to render multiple views in different containers.

    <router-outlet name="primary"></router-outlet>  
    <router-outlet name="sidebar"></router-outlet>  
    

    This way, you can create layouts with multiple views.

    <router-outlet>is essential in Angular for navigation and dynamic component loading. It enables the creation of complex applications with nested routes, lazy loading, and multiple views.

    Select Menu