Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Saturday, June 29, 2024

Mutable functions in JavaScript

In JavaScript, mutable functions are those that can alter the state of objects or variables passed to them. Here are a few examples:
Example 1: Modifying an Object
function updatePerson(person) {
  person.name = "John Doe";
  person.age = 30;
}

let person = { name: "Jane", age: 25 };
updatePerson(person);

console.log(person); // Output: { name: "John Doe", age: 30 }
Example 2: Modifying an Array
function addToArray(arr, value) {
  arr.push(value);
}

let numbers = [1, 2, 3];
addToArray(numbers, 4);

console.log(numbers); // Output: [1, 2, 3, 4]
Example 3: Changing Object Properties
function updateCar(car) {
  car.color = "red";
  car.model = "Sedan";
}

let car = { color: "blue", model: "SUV" };
updateCar(car);
console.log(car); // Output: { color: "red", model: "Sedan" }
Example 4: MutatingElements in an Array
function doubleArrayElements(arr) {
  for (let i = 0; i < arr.length; i++) {
    arr[i] = arr[i] * 2;
  }
}

let values = [1, 2, 3];
doubleArrayElements(values);
console.log(values); // Output: [2, 4, 6]
Example 5: Adding Properties to an Object
function addProperty(obj, key, value) {
  obj[key] = value;
}

let book = { title: "1984" };
addProperty(book, "author", "George Orwell");

console.log(book); // Output: { title: "1984", author: "George Orwell" }
In these examples, the functions directly modify the state of the objects or arrays passed to them, demonstrating the concept of mutability in JavaScript.

Immutable Functions in JavaScript

An immutable function in JavaScript is a function that does not modify the data passed to it as arguments. Instead, it returns a new data structure with the changes applied, leaving the original data unchanged. This concept is crucial in functional programming and helps avoid side effects, making the code more predictable and easier to debug.

Examples of Immutable Functions
Example 1: Immutable Update to an Object
const person = {
  name: "Alice",
  age: 30
};

const updateAge = (obj, newAge) => {
  return {
    ...obj,
    age: newAge
  };
};

const updatedPerson = updateAge(person, 31);

console.log(person); // { name: "Alice", age: 30 }
console.log(updatedPerson); // { name: "Alice", age: 31 }
In this example, the updateAge function does not modify the original person object. Instead, it creates a new object with the updated age.
Example 2: Immutable Update to an Array

const numbers = [1, 2, 3];
const addNumber = (arr, num) => {
  return [...arr, num];
};

const newNumbers = addNumber(numbers, 4);

console.log(numbers); // [1, 2, 3]
console.log(newNumbers); // [1, 2, 3, 4]
Here, the addNumber function returns a new array with the new number added, leaving the original numbers array unchanged.

Benefits of Immutable Functions
  1. Predictability: Since immutable functions do not modify the original data, the same input will always produce the same output, making the code easier to understand and predict.
  2. Debugging: Easier to trace the flow of data and identify where things might have gone wrong since the original data remains unchanged.
  3. Concurrency: Immutable data structures are inherently thread-safe, making it easier to work with concurrency and parallelism.
  4. Undo/Redo: Immutable updates make it easier to implement features like undo and redo, as each change creates a new state rather than modifying the current state.
Using immutability in JavaScript often involves the use of methods that return new objects or arrays rather than modifying the originals. Some commonly used immutable methods include map, filter, reduce, and the spread operator (...).
Look at mutable functions in JavaScript click here.

Higher Order function in JavaScript

In JavaScript, a higher-order function is a function that does at least one of the following:
  1. Takes one or more functions as arguments.
  2. Returns a function as its result.
Higher-order functions are a key feature of functional programming and are widely used in JavaScript.

Note that because of HOF, JavaScript functions are first-class citizens because they can be used as argument and as return value of a function. In other words, JavaScript functions act as data/variables.

Examples of Higher-Order Functions
1. Functions as Arguments
Higher-order functions can take other functions as arguments. Common examples include array methods like map, filter, and reduce.
Example: Using map
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(function(n) {
  return n * 2;
});

console.log(doubled); // [2, 4, 6, 8, 10]
2. Functions as Return Values
Higher-order functions can also return functions. This is useful for creating function factories or for partial application.
Example: Function that Returns Another Function
function createMultiplier(multiplier) {
  return function(x) {
    return x * multiplier;
  };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5)); // 10
console.log(triple(5)); // 15
3. Combining Functions
You can use higher-order functions to combine simple functions into more complex ones.
Example: Function Composition
function compose(f, g) {
  return function(x) {
    return f(g(x));
  };
}

function add1(x) {
  return x + 1;
}

function multiply2(x) {
  return x * 2;
}

const add1ThenMultiply2 = compose(multiply2, add1);
console.log(add1ThenMultiply2(5)); // 12
Practical Uses of Higher-Order Functions

1. Event Handling in Web Development
   Higher-order functions are commonly used in event handling. For instance, you might pass a callback function to an event listener.
  document.getElementById('button').addEventListener('click', function() {
     console.log('Button clicked!');
   });   
2. Asynchronous Programming
   They are also used in asynchronous programming with promises.
   fetch('https://api.example.com/data')
     .then(response => response.json())
     .then(data => {
       console.log(data);
     })
     .catch(error => {
       console.error('Error:', error);
     });
3. Functional Programming Paradigms
   Higher-order functions are essential in functional programming, allowing for more concise and readable code.
   const numbers = [1, 2, 3, 4, 5];
   const evenNumbers = numbers.filter(n => n % 2 === 0);
   console.log(evenNumbers); // [2, 4]
Conclusion:
Higher-order functions are a powerful feature in JavaScript, enabling more abstract and flexible code. They allow you to manipulate functions just like any other data type, leading to more modular and reusable code.

Pure function in JavaScript

A pure function in JavaScript is a function that always returns the same result given the same input and doesn't have any side effects. This means it doesn't modify anything outside its scope, like global variables or objects passed by reference. Pure functions are predictable, making code easier to understand and test.

Conditions for pure function in JS

A pure function has the following characteristics:

1. Deterministic: For the same input, it always returns the same output. This means the function does not rely on any external state or variables that might change.

2. No Side Effects: The function does not cause any observable side effects. This includes:
  • Not modifying any external variables or state (such as global variables, objects, or arrays passed by reference).
  • Not performing any I/O operations (like logging to the console, writing to a file, or making network requests).

Example of a pure function in JavaScript:
function add(a, b) {
  return a + b;
}

// Calling add with the same arguments will always return the same result
console.log(add(2, 3)); // Output: 5
console.log(add(2, 3)); // Output: 5
Example of an impure function:
let counter = 0;
function incrementCounter() {
  counter += 1;
  return counter;
}

// Calling incrementCounter will return different results due to changing external state
console.log(incrementCounter()); // Output: 1
console.log(incrementCounter()); // Output: 2
To summarize, a pure function adheres to the following conditions:
  • Always produces the same output for the same input.
  • Has no side effects.

JavaScript Default Export vs Named Export in modules

In JavaScript modules, you can export values from a file using either default export or named exports. Each approach serves different purposes and has its own syntax for importing and exporting values.

Default Export:

1. Purpose: Default export is used to export a single value, function, or object from a module. It is commonly used when a module only needs to export one main entity.

2. Syntax:
   // In the exporting file
   export default myFunction;
   export default myValue;
   export default { key: value };

   // In the importing file
   import myDefaultExport from './module';
3. Usage:
   // In the exporting file (e.g., module.js)
   const myValue = 10;
   export default myValue;

   // In the importing file
   import myValue from './module.js';
   console.log(myValue); // Output: 10
Named Export:

1. Purpose: Named exports are used to export multiple values, functions, or objects from a module. They allow you to export several entities from a single module.

2. Syntax:
   // In the exporting file
   export { value1, value2, ... };

   // In the importing file
   import { value1, value2 } from './module';
3. Usage:
   // In the exporting file (e.g., module.js)
   export const value1 = 'foo';
   export const value2 = 'bar';

   // In the importing file
   import { value1, value2 } from './module.js';
   console.log(value1); // Output: 'foo'
   console.log(value2); // Output: 'bar'
Comparison:
  • Default Export: Typically used for exporting a single value or entity from a module. When importing, you can choose any name for the imported value.
  • Named Export: Used for exporting multiple values or entities from a module. When importing, you must use the exact names specified in the export statement.
Both default and named exports are powerful features of JavaScript modules, allowing you to structure and organize your code effectively and facilitate code reuse across your application. Choose the appropriate export method based on the specific requirements of your module.

How can we alias Named Export?
You can alias named exports when importing them in JavaScript. This can be useful if you want to use a different name for an exported value or if you want to avoid naming conflicts.

Here's how you can alias named exports:
// In the exporting file (e.g., module.js)
export const originalName = 'foo';

// In the importing file
import { originalName as aliasName } from './module';
console.log(aliasName); // Output: 'foo'
In this example, we're importing the named export originalName from the module.js file and aliasing it as aliasName. Now, when we refer to aliasName in our code, it will behave exactly the same as if we were referring to originalName.

This aliasing feature is particularly helpful when you have multiple modules with similar or conflicting names, or when you want to provide a more descriptive or meaningful name for an imported value in your code.

CommonJS and ES6 modules

CommonJS:

CommonJS is a module system for JavaScript used primarily in server-side environments like Node.js. It specifies a way to organize and structure JavaScript code into reusable modules, making it easier to manage large-scale applications. With CommonJS, modules can export values and functions using module.exports and import them using the require function. This allows for better code organization, encapsulation, and reusability.

CommonJS was introduced in 2009 by Kevin Dangoor, Isaac Z. Schlueter, and others. It aimed to address the lack of a standard module system in JavaScript, particularly for server-side development.

How can functions be exported using Common JS
In CommonJS, functions (or any value) can be exported from a module using the module.exports object. Here's an example of exporting a function:
// myModule.js
function myFunction() {
  // Function logic here
}

module.exports = myFunction;
In this example, the myFunction is defined within the module, and then it's assigned to module.exports, making it available for other modules to import.

How can a JS file become a module using Common JS
To make a JavaScript file a module using CommonJS, you typically define your functions, variables, or other components within the file, and then export them using module.exports or exports. Here's a basic example:
// myModule.js

// Define a function
function greet(name) {
  return "Hello, " + name + "!";
}

// Export the function
module.exports = greet;
In this example, greet function is defined and then exported using module.exports. This file (myModule.js) can now be imported into other files using require:
// anotherFile.js

// Import the module
const greet = require('./myModule');

// Use the imported function
console.log(greet("Alice")); // Output: Hello, Alice!
In anotherFile.js, require('./myModule') imports the greet function from myModule.js, allowing you to use it within anotherFile.js.

How can multiple data and functions be exported using Common JS
In CommonJS, you can export multiple data and functions by assigning them as properties of the module.exports object. Here's an example:
// myModule.js

// Define a function
function greet(name) {
  return "Hello, " + name + "!";
}

// Define a variable
const version = "1.0";

// Export multiple items
module.exports = {
  greet: greet,
  version: version
};
In this example, both the greet function and the version variable are exported as properties of the module.exports object. 

Alternatively, you can use the shorthand property definition in ES6:
// myModule.js

// Define a function
function greet(name) {
  return "Hello, " + name + "!";
}

// Define a variable
const version = "1.0";

// Export multiple items using ES6 shorthand
module.exports = {
  greet,
  version
};
In both cases, you can import and use these exported items in other files using require:
// anotherFile.js

// Import the module
const myModule = require('./myModule');

// Use the imported function and variable
console.log(myModule.greet("Alice")); // Output: Hello, Alice!
console.log(myModule.version); // Output: 1.0
Differences between ES6 modules and CommonJS:
ES6 introduced import and export for module data and functions import and export. It does differ from common JS. ES6 introduced a native module system for JavaScript, which includes import and export statements, providing a more standardized and modern approach to modularizing JavaScript code. Here are some key differences between ES6 modules and CommonJS:

1. Syntax: ES6 modules use import and export statements to define dependencies and exports, respectively, while CommonJS uses require to import modules and module.exports or exports to export values.

2. Static vs. Dynamic: ES6 modules are statically analyzed, meaning imports and exports are resolved at compile time. This allows tools to statically analyze the code for optimizations like tree-shaking, removing unused exports. CommonJS, on the other hand, is dynamically loaded, so dependencies are resolved at runtime.

3. Immutable Bindings: In ES6 modules, imported bindings are immutable, meaning you cannot change the value of an imported binding. This helps prevent unintended side effects. In CommonJS, imported values are mutable, so changing them can affect other modules that import the same value.

4. Async Module Loading: ES6 modules support dynamic import(), allowing modules to be loaded asynchronously. This can be useful for lazy loading modules or conditionally loading them based on runtime conditions. CommonJS does not have built-in support for asynchronous module loading.

5. Browser Support: While CommonJS is primarily used in server-side environments like Node.js, ES6 modules are supported in modern browsers natively. However, support for ES6 modules in browsers may require using a module bundler like Webpack or Rollup to handle compatibility with older browsers and optimize code.

Overall, ES6 modules provide a more standardized, efficient, and modern approach to modularizing JavaScript code, but CommonJS remains widely used, especially in Node.js environments where ES6 module support is still evolving.

In JavaScript, one file one module. What does it mean?
In JavaScript, the principle of "one file, one module" means that each JavaScript file typically corresponds to a single module. This modular approach helps organize code by breaking it into smaller, more manageable pieces, with each module encapsulating related functionality.

With this principle:

1. Modularity: Each file focuses on a specific aspect of functionality, making it easier to understand, maintain, and reuse code.

2. Encapsulation: Modules encapsulate their internal logic, exposing only the necessary interfaces (functions, variables) to other parts of the program. This helps prevent unintended interactions between different parts of the codebase.

3. Dependency Management: Modules can depend on each other, and the dependencies are explicitly declared either through import (in ES6 modules) or require (in CommonJS modules). This makes it clear which modules rely on others, simplifying dependency management.

4. Scoping: Each module has its own scope, meaning variables and functions defined within a module are not accessible outside of it unless explicitly exported. This helps avoid naming conflicts and polluting the global namespace.

Following the "one file, one module" principle promotes code organization, maintainability, and scalability in JavaScript projects, facilitating collaboration among developers and reducing the risk of errors.

JavaScript modules

In JavaScript, a module is a reusable piece of code that can be exported from one program and imported for use in another program. Modules help in organizing code, managing dependencies, and maintaining the codebase by splitting it into smaller, manageable, and reusable components.

Types of Modules in JavaScript

There are mainly two types of modules in JavaScript:

1. ES6 (ECMAScript 2015) Modules:
ES6 introduced a standard way to define modules in JavaScript. These modules are commonly known as ECMAScript modules (ESM). They use import and export statements to include and share code between files.

- Exporting:
  // Named export
  export const myVariable = 42;
  export function myFunction() {
    // ...
  }

  // Default export
  export default function() {
    // ...
  }
- Importing:
  // Named import
  import { myVariable, myFunction } from './myModule.js';

  // Default import
  import myDefaultFunction from './myModule.js';

  // Import everything as an object
  import * as myModule from './myModule.js';


2. CommonJS Modules:
CommonJS is a module system primarily used in Node.js. It uses require to import modules and module.exports or exports to export modules.

- Exporting:
  // Using module.exports
  module.exports = {
    myVariable: 42,
    myFunction: function() {
      // ...
    }
  };

  // Using exports
  exports.myVariable = 42;
  exports.myFunction = function() {
    // ...
  };

- Importing:

  const myModule = require('./myModule.js');
  const myVariable = myModule.myVariable;
  const myFunction = myModule.myFunction;

Comparison:
- ES6 Modules:
  • Native support in modern browsers and JavaScript engines.
  • Static module structure, which allows for static analysis and tree shaking (removing unused code).
  • Can be used both in the browser and in Node.js (with proper configuration).
- CommonJS Modules:
  • Widely used in Node.js environments.
  • Dynamic module loading, which can lead to more flexible but less optimizable code.
  • Not natively supported in browsers without a bundler or transpiler.
Other Module Systems:
- AMD (Asynchronous Module Definition):
  • Mainly used in browsers.
  • Uses define and require functions.
Example:
  
    define(['dependency'], function(dependency) {
      const myModule = {};
      return myModule;
    });
  

- UMD (Universal Module Definition):
  •   A hybrid module format that works with both CommonJS and AMD.
  Example:
  
    (function (root, factory) {
      if (typeof define === 'function' && define.amd) {
        // AMD
        define(['dependency'], factory);
      } else if (typeof module === 'object' && module.exports) {
        // CommonJS
        module.exports = factory(require('dependency'));
      } else {
        // Browser globals
        root.myModule = factory(root.dependency);
      }
    }(this, function (dependency) {
      const myModule = {};
      return myModule;
    }));
  

Using Modules in the Browser: To use ES6 modules in the browser, you can use the type="module" attribute in the <script> tag.

  <script type="module">
    import { myFunction } from './myModule.js';
    myFunction();
  </script>


Using Modules in Node.js: By default, Node.js uses CommonJS. To use ES6 modules, you need to set "type": "module" in the package.json file or use the .mjs file extension.

  {
    "type": "module"
  }

Modules play a crucial role in JavaScript development, allowing developers to build modular, maintainable, and scalable applications.

More about CommonJS and ES6 modules are given in the next post.

Binding methods in JavaScript

What is meant by binding a method.
In JavaScript, binding a method refers to the process of associating a function with a particular object. This ensures that when the function is called, it maintains the context of that object, meaning 'this' inside the function refers to the object it's bound to.

How do we bind a method in JavaScript?
There are a few ways to bind a method in JavaScript:

1. Using the bind() method: The bind() method creates a new function that, when called, has its 'this' keyword set to a specific value. Here's an example:
const obj = {
  name: 'Albert',
  greet: function() {
    console.log('Hello, ' + this.name);
  }
};

const boundGreet = obj.greet.bind(obj);
boundGreet(); // Output: Hello, Albert
Note that bind method does not execute greet method of obj immediately; rather it creates a new method called boundGreet which can be executed later when required.

2. Using arrow functions: Arrow functions inherit 'this' from the enclosing lexical context, so they can be used to maintain the context of the object without explicitly binding it. Here's an example:
const obj = {
  name: 'Albert',
  greet: function() {
    const innerFunction = () => {
      console.log('Hello, ' + this.name);
    };
    innerFunction();
  }
};

obj.greet(); // Output: Hello, Albert
In the above example greet method of obj is executed immediately; now the arrow function named innerFunction gets the value of this from from its enclosing lexical context.

3. Binding the method during function call: You can also bind the method directly during its invocation using call() or apply() methods. Here's an example:
const obj = {
  name: 'Albert',
  greet: function() {
    console.log('Hello, ' + this.name);
  }
};

const anotherObj = { name: 'Rita' };
obj.greet.call(anotherObj); // Output: Hello, Rita
In the above example greet method of obj is executed using call method. The value of this is derived from the parameter passed to call method.

Each of these methods allows you to control the context ('this' value) in which a method executes, ensuring consistent behavior and avoiding context-related bugs.

Difference between call and apply methods.
The call() and apply() methods in JavaScript are used to invoke functions with a specific 'this' context, along with arguments (for apply()) or individual parameters (for call()). They are similar in function but differ in how they accept arguments.

Here's a breakdown of each:
1. call(thisArg, arg1, arg2, ...): This method calls a function with a specified 'this' value and individual arguments. The first argument ('this'Arg) is the value to be passed as 'this' to the function being called. Any subsequent arguments are passed to the function as individual parameters.

Example:
function greet(message) {
  console.log(message + ', ' + this.name);
}

const person = { name: 'Albert' };
greet.call(person, 'Hello'); // Output: Hello, Albert

2. apply(thisArg, [argsArray]): This method is similar to call(), but it accepts arguments as an array. The first argument (thisArg) is the value to be passed as 'this' to the function being called, and the second argument (argsArray) is an array or an array-like object containing the arguments to be passed to the function.

Example:
function greet(message) {
  console.log(message + ', ' + this.name);
}

const person = { name: 'Albert' };
const args = ['Hello']; // Arguments in an array
greet.apply(person, args); // Output: Hello, Albert

In general, call() is more commonly used when the number of arguments is known upfront and specified individually, while apply() is useful when the number of arguments may vary or when the arguments are already available in an array-like structure.

Both call() and apply() are powerful tools for controlling the execution context of functions in JavaScript, particularly when working with object-oriented programming patterns or when integrating code that may have been written with a different context in mind.

Question:
Is the following okay
const obj = {
  name: 'Albert',
  greet: function() {
    console.log('Hello, ' + this.name);
  }
};

obj.greet();

Yes, the code you provided is perfectly fine. It defines an object obj with a property name set to 'Albert' and a method greet() that logs a greeting message using the name property of the object. Then, it calls the greet() method of the obj object, which logs 'Hello, Albert' to the console.

This code demonstrates a common pattern in JavaScript for creating objects with properties and methods. The method greet() accesses the name property of the object using 'this', which refers to the object itself, allowing for dynamic access to its properties.

Question: 
how the following 
const boundGreet = obj.greet.bind(obj);
boundGreet(); // Output: Hello, Albert
is different from the obj.greet();

In both cases, obj.greet() and boundGreet() will output the same result: 'Hello, Albert'. However, the way they achieve 'this' result is slightly different due to the use of bind().

1. obj.greet(): This directly calls the greet() method of the obj object. Inside the greet() method, 'this' refers to the obj object itself because the method is being called from it. So, when obj.greet() is called, this.name inside greet() refers to 'Albert', and 'Hello, Albert' is logged to the console.

2. const boundGreet = obj.greet.bind(obj); boundGreet();: Here, bind(obj) creates a new function where 'this' is permanently set to the obj object. This means that when boundGreet() is called, it will always execute in the context of the obj object, regardless of how or where it's called from. So, boundGreet() behaves essentially the same as obj.greet(), outputting 'Hello, Albert'.

The primary difference is that bind() allows you to create a new function with a fixed context ('this' value), which can be useful when you want to pass the method around as a callback without worrying about its context changing. It's particularly handy when working with event listeners or passing methods as arguments to other functions.

Now for 
function greet(message) {
  console.log(message + ', ' + this.name);
}

Explain greet.call(person, 'Hello'); vs greet('Hello'); 

Sure, let's break down the difference between greet.call(person, 'Hello') and greet('Hello'):

1. greet.call(person, 'Hello'):
This line invokes the greet function with person as the this value. It also passes 'Hello' as an argument to the message parameter of the greet function.
Inside the greet function, this.name refers to the name property of the person object because person is explicitly passed as the 'this' context via the call() method.
So, 'Hello' is concatenated with the name property of the person object, and the resulting string is logged to the console.

2. greet('Hello'):
This line simply calls the greet function with 'Hello' as an argument for the message parameter.
Since no explicit binding is applied, the 'this' context within the greet function depends on how the function is called. In non-strict mode, if 'this' is not set by the call, it defaults to the global object (window in a browser, global in Node.js), or undefined in strict mode.
If used in a browser environment, this.name would likely result in an error because the global object (window) doesn't have a name property. If used in Node.js, it would likely log undefined, unless name is defined in the global context or you're in a module scope where 'this' would be undefined.
In both cases, without explicit binding, this.name would typically not refer to the intended name property of any specific object.

So, the difference lies in how the 'this' context is determined within the greet function. call() allows you to explicitly set the 'this' context, while calling the function directly relies on the default behavior of this.

JavaScript compilers

What are different JS compilers?
There are several JavaScript compilers available, each serving different purposes and catering to specific needs of developers. Here are some of the most commonly used JavaScript compilers:

1. Babel: Babel is one of the most popular JavaScript compilers used primarily for transpiling modern JavaScript code (ES6+ syntax) into backwards-compatible versions that can run in older browsers. It enables developers to use the latest JavaScript features without worrying about compatibility issues.

2. TypeScript: TypeScript is a superset of JavaScript that adds static typing to the language. It includes its own compiler that translates TypeScript code into plain JavaScript. TypeScript helps developers catch errors early in the development process and write more maintainable code by providing type checking and other features not available in standard JavaScript.

3. Closure Compiler: Developed by Google, Closure Compiler is a tool for optimizing JavaScript code. It analyzes and minimizes JavaScript code to improve performance, reduce file size, and obfuscate code for deployment. Closure Compiler performs advanced optimizations, such as dead code elimination, function inlining, and variable renaming.

4. CoffeeScript: CoffeeScript is a programming language that compiles down to JavaScript. It aims to make writing JavaScript code more concise and readable by providing a more expressive syntax with features inspired by Ruby and Python. CoffeeScript code is converted into equivalent JavaScript code, allowing developers to leverage its syntax while still targeting the JavaScript runtime.

5. Webpack: While not strictly a JavaScript compiler, Webpack is a module bundler that can transform and optimize JavaScript code as part of its build process. It supports various loaders and plugins for tasks such as transpilation, minification, and code splitting, making it a versatile tool for managing JavaScript assets in complex web applications.

6. Rollup: Rollup is another module bundler like Webpack, but it's designed with a focus on producing smaller, more efficient bundles for libraries and applications. Rollup uses tree-shaking techniques to eliminate dead code and optimize bundle size, making it well-suited for building JavaScript libraries and packages for distribution.

These are just a few examples of JavaScript compilers available in the ecosystem. Each compiler has its own strengths and use cases, and developers often choose the one that best fits their project requirements and development workflow.

Monday, June 24, 2024

Asynchronous Programming in JavaScript

Asynchronous programming in JavaScript allows for non-blocking code execution, meaning that tasks can run concurrently without waiting for each one to complete before starting the next. This is essential for tasks like network requests, file reading/writing, or interacting with databases. Here are the primary approaches to asynchronous programming in JavaScript:

1. Callbacks: Callbacks are functions passed as arguments to other functions and are executed once an asynchronous operation is completed. This is the traditional way of handling asynchronous operations in JavaScript.

Example:

function fetchData(callback) {
  setTimeout(() => {
    const data = "some data";
    callback(data);
  }, 1000);
}

fetchData((data) => {
  console.log(data); // Output: some data
});

Pros:

  1. Simple and easy to understand for small tasks.
  2. Well-supported and widely used in many libraries.

Cons:

  1. Can lead to "callback hell" or "pyramid of doom" when dealing with multiple nested callbacks.
  2. Error handling can become complex and messy.

2. Promises: Promises provide a more robust way to handle asynchronous operations by representing a value that may be available now, or in the future, or never. Promises have three states: pending, fulfilled, and rejected.

Example:

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const data = "some data";
      resolve(data);
    }, 1000);
  });
}

fetchData()
  .then((data) => {
    console.log(data); // Output: some data
  })
  .catch((error) => {
    console.error(error);
  });

Pros:

  1. Avoids callback hell.
  2. Chainable with '.then()' for sequencing asynchronous tasks.
  3. Improved error handling with '.catch()'.

Cons:

  1. Can still become complex with many '.then()' and '.catch()' chains.
  2. Requires understanding of the promise states and methods.

3. Async/Await
Async/await is syntactic sugar built on top of Promises, introduced in ECMAScript 2017 (ES8). It allows writing asynchronous code that looks and behaves more like synchronous code, making it easier to read and maintain.

Example:

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const data = "some data";
      resolve(data);
    }, 1000);
  });
}

async function getData() {
  try {
    const data = await fetchData();
    console.log(data); // Output: some data
  } catch (error) {
    console.error(error);
  }
}

getData();

Pros:

  1. Cleaner and more readable code.
  2. Easier to understand and maintain.
  3. Simplifies error handling with try/catch.

Cons:

  1. Requires understanding of Promises since async/await is built on top of them.
  2. All functions using 'await' must be marked as 'async'.

4. Event Loop and Microtasks: Understanding the event loop is crucial for mastering asynchronous programming in JavaScript. The event loop handles the execution of multiple chunks of your program over time. Tasks are placed in the task queue and executed by the event loop when the call stack is empty.

Microtasks:
Microtasks are a special kind of task that needs to be executed after the current execution context completes but before any rendering or other tasks are processed. Promises and mutation observers use microtasks.

Example:

console.log("Start");

setTimeout(() => {
  console.log("Timeout");
}, 0);

Promise.resolve().then(() => {
  console.log("Promise");
});

console.log("End");

Output:

  • Start
  • End
  • Promise
  • Timeout


Explanation:

  • "Start" and "End" are logged first because they are synchronous.
  • The promise resolves before the timeout because promises are microtasks and are executed before tasks like 'setTimeout'.

Pros:

  1. Fundamental understanding of how JavaScript handles asynchronous operations.
  2. Essential for writing performant and efficient code.

Cons:

  1. Can be complex to understand initially.
  2. Requires knowledge of the JavaScript runtime and execution model.

Conclusion: 

Each approach to asynchronous programming in JavaScript has its use cases and trade-offs. Callbacks are simple but can lead to complex code structures. Promises provide a better way to manage asynchronous code but can still be verbose. Async/await offers a cleaner and more readable way to write asynchronous code but requires an understanding of Promises and the event loop. Understanding these methods and when to use them will help you write efficient and maintainable asynchronous JavaScript code.

let keyword in JavaScript

The 'let' keyword in JavaScript is used to declare block-scoped variables. It was introduced in ECMAScript 6 (ES6) and offers a way to create variables that are limited in scope to the block, statement, or expression where they are defined. This is different from the 'var' keyword, which declares a variable globally or locally to an entire function regardless of block scope.

Here are some key points about the 'let' keyword:


1. Block Scope: A variable declared with 'let' is only available within the block it is defined. A block is a section of code enclosed by '{}'.
if (true) {
let x = 10;
console.log(x); // 10
}
console.log(x); // ReferenceError: x is not defined

2. Hoisting: Unlike variables declared with 'var', variables declared with 'let' are not hoisted to the top of their block. Instead, they are hoisted to the top of the block but are not initialized. This means you cannot access a 'let' variable before you declare it within its block.
console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 5;

3. No Redeclaration: A variable declared with 'let' cannot be redeclared within the same scope. This is in contrast to 'var', which allows for redeclaration.
let a = 1;
let a = 2; // SyntaxError: Identifier 'a' has already been declared

4. Temporal Dead Zone (TDZ): The time between entering the scope and the actual declaration of the variable is called the Temporal Dead Zone. During this period, any reference to the variable will result in a ReferenceError.
{
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 3;
}

5. Reassignment: Variables declared with 'let' can be reassigned.
let c = 4;
c = 5; // Valid
console.log(c); // 5

6. Global Scope: When 'let' is used to declare a variable at the top level of a script, it does not create a property on the global object (e.g., 'window' in browsers).
let d = 6;
console.log(window.d); // undefined

Overall, 'let' provides better scoping rules and helps avoid issues related to variable hoisting and redeclaration, making your code more predictable and easier to maintain.

const keyword in JavaScript

The 'const' keyword in JavaScript is used to declare variables that are meant to be constant and cannot be reassigned. Here are some key points about the 'const' keyword:

1. Immutable Bindings: When a variable is declared with 'const', it cannot be reassigned a different value. This does not mean that the value itself is immutable. For example, if the value is an object or an array, the properties of the object or the elements of the array can still be modified.

const x = 10;
x = 20; // This will cause an error

const obj = { a: 1 };
obj.a = 2; // This is allowed, the object itself is mutable

2. Block Scope: Variables declared with 'const' have block scope, which means they are only accessible within the block where they are declared. A block is defined by a pair of curly braces '{}'.

if (true) {
const y = 5;
console.log(y); // 5
}
console.log(y); // This will cause an error, y is not defined

3. Declaration and Initialization: A 'const' variable must be initialized at the time of declaration. It cannot be declared without initialization.

const z; // This will cause an error
const z = 15; // This is correct

4. Reference Type Mutability: As mentioned earlier, if a 'const' variable holds a reference to an object or array, the reference cannot be changed, but the contents of the object or array can be modified.

const arr = [1, 2, 3];
arr.push(4); // This is allowed
console.log(arr); // [1, 2, 3, 4]

arr = [5, 6, 7]; // This will cause an error

5. Temporal Dead Zone (TDZ): Like 'let', 'const' has a temporal dead zone, which means the variable cannot be accessed before its declaration in the code.

console.log(a); // This will cause a ReferenceError
const a = 3;

Using 'const' is beneficial because it makes your code more predictable by ensuring that variables intended to remain constant do not get reassigned accidentally. However, it is important to understand that 'const' does not make the value itself immutable if it is a reference type like an object or array. To achieve full immutability, you can use methods such as 'Object.freeze' for objects.

Scopes in JavaScript

In JavaScript, scope determines the accessibility (visibility) of variables, functions, and objects in some particular part of your code during runtime. There are several types of scope in JavaScript:

1. Global Scope:
Variables declared outside any function have global scope. They are accessible from anywhere in the code.
In a browser, global variables become properties of the 'window' object.

var globalVar = "I'm a global variable";
function globalScopeTest() {
  console.log(globalVar); // Accessible
}
globalScopeTest();
console.log(globalVar); // Accessible

2. Function Scope:
Variables declared inside a function are local to that function and cannot be accessed from outside the function.
Function scope applies to variables declared with 'var'.

function functionScopeTest() {
  var functionVar = "I'm a function-scoped variable";
  console.log(functionVar); // Accessible
}

functionScopeTest();
console.log(functionVar); // Uncaught ReferenceError: functionVar is not defined

3. Block Scope:
Block scope is created by 'let' and 'const' inside blocks delimited by '{}' (like in loops, 'if' statements, etc.).
Variables declared with 'let' or 'const' are only accessible within that block.

{
  let blockVar = "I'm a block-scoped variable";
  console.log(blockVar); // Accessible
}

console.log(blockVar); // Uncaught ReferenceError: blockVar is not defined

4. Lexical Scope:
Lexical scope means that inner functions have access to variables and functions declared in their outer scope.
This is determined by the physical placement of the function within the nesting of scopes.

function outerFunction() {
  var outerVar = "I'm an outer variable";
  function innerFunction() {
    console.log(outerVar); // Accessible due to lexical scoping
  }
  innerFunction();
}

outerFunction();

5. Module Scope:
Variables declared inside an ES6 module are scoped to that module.
This means they are not accessible from other scripts unless explicitly exported and imported.

// myModule.js
const moduleVar = "I'm a module-scoped variable";

export function getModuleVar() {
  return moduleVar;
}

// main.js
import { getModuleVar } from "./myModule.js";
console.log(getModuleVar()); // Accessible

Scope Chain and Closures

Scope Chain:
When trying to access a variable, JavaScript first looks in the current scope. If it does not find the variable, it looks in the outer scope, and so on, up the chain until it reaches the global scope.

Closures:
A closure is a function that retains access to its lexical scope, even when that function is executed outside its original scope.
This allows functions to maintain state across different invocations.

function makeCounter() {
  let count = 0;

  return function () {
    count++;
    return count;
  };
}

const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

Understanding these different scopes is crucial for managing variables and avoiding common issues like variable shadowing, where a variable in a local scope can unintentionally override a variable in an outer scope, and memory leaks caused by unintended references in closures.

Friday, June 21, 2024

Introduction to AJAX

Introduction to AJAX (Asynchronous JavaScript and XML)

Normally a web browser requests a web page from web server and the web server responds by returning the requested web page. As soon as the web page loads in to the browser, the connection between the web browser and the web server is terminated.

This is the traditional web model used in the communication between the web server and browser. If a request is made for the same or another page, the same process is repeated again.

Whenever a request is sent by the user for a page, the existing page has to be reloaded to display the new information. New information or a new page is displayed only after the page is reloaded. Sometimes this process is very annoying for the user experience because entire page is rendered again.

If you are creating a large web application like YouTube, then obviously there will be a lot of web elements in it. In such a situation, if the page is reloaded repeatedly while interacting with every small element, then your web application will create very bad user experience.

For example, suppose that you are watching a video on YouTube. You like this video and you click on the Like button to like it. If the entire page reloads as soon as you click on the Like button, you will not like it at all. Maybe you would never click the Like button. But this does not happen. Whenever you click the Like button for a video while watching the YouTube video, the page does not reload; only the Like button is updated and the number of likes is increased. The video continues to play without any problem. How does this happen? YouTube uses AJAX for this. 

So the question is : what is AJAX?

The full form of AJAX is Asynchronous JavaScript and XML. You can call it a set of techniques or methodology which is used to create asynchronous web pages using several web technologies (HTML & CSS, JavaScript, DOM, XML). 

Now the question is: What are asynchronous web pages?

Asynchronous web pages are such web pages in which the entire page does not need to be loaded for some elements to be updated. New content is dynamically loaded into the web page. In such pages, processing is done in the background. The user does not feel any interference while happening this process. So the question is: how does this happen? You will know about this in the AJAX Working section. Before that, let us try to know about the core components, advantages and disadvantages of AJAX.

Core Components of AJAX

As I told you earlier, in AJAX, many technologies are combined together to generate asynchronous web pages. These technologies are the core components of AJAX. They are given below.

  • HTML & CSS - HTML and CSS are used for presentation. By using HTML and CSS, you can design a beautiful web page.
  • JavaScript - It is used to generate client side events which are handled and processed by JavaScript.
  • DOM (Document Object Model) - DOM is used to access data from inside the page and to present data dynamically.
  • XMLHttpRequest Object - This object is used to send and receive data asynchronously to the server.

Advantages of AJAX

Below are given some advantages of AJAX.

  • With the help of AJAX, you can create fast, dynamic websites.
  • Because JavaScript is a client side scripting language, so all the processing does not happen on the server only. Some process also happens on the client machine. This reduces the load on the server and makes processing fast.
  • Better user experience is possible through AJAX because AJAX does processing in the background. This does not interfere with the user activities. The page does not hang to receive data from server.
  • With AJAX, you have open source JavaScript libraries available which you can use to improve your web application.

Disadvantages of AJAX

Some disadvantages of AJAX are given below.

  • If JavaScript is disabled in the user's web browser, AJAX based web application will not work.
  • Because the data of the web page is loaded dynamically, it is not a part of the web page. This is the reason why search engines cannot see such data and do not index it.
  • When you use AJAX, the Back and Refresh buttons do not function properly.
  • Due to asynchronous mode, if the server takes time to process, then the page looks annoying.

Working of AJAX

The working of AJAX is explained by a diagram below.

As you can see in the diagram above, the first request by the web browser and the first response by the web server are processed like a traditional web model. After this, the subsequent requests, whenever data has to be fetched back from the server, this task is done by sending a request locally through JavaScript.

For example, if the server has to update when the user clicks on the like button, then for this the onclick event of JavaScript has to be handled. When this event is generated, event handler function is called. In this function, you will pass this request to the server using the XMLHttpRequest Object.

This request reaches the server through the AJAX engine. You will be told about this object in a separate tutorial.

The AJAX engine is on the client side only. The AJAX engine is nothing but a combination of JavaScript and XMLHttpRequest object. The AJAX engine will establish a connection to the server in background and update the page e.g. the number of likes on the page.

The AJAX engine performs this task without disturbing the web page. The server will send the updated data back to the AJAX engine. Any format from HTML to XML and JSON can be processed by AJAX engine. JavaScript updates the same element with the data sent by AJAX engine.

Where are AJAX used

AJAX has been used by many big web applications. For example, when you search a term on Google, the suggestions shown to you are shown by AJAX only. As soon as you type a term, AJAX works in the background and fetches suggestions for you from the server.

Another example of AJAX is YouTube or Facebook like button. When you like a post or video, the number of likes increases without reloading the page. This is also done by AJAX.

Introduction to XMLHttpRequest Object

XMLHttpRequest is an API in the form of a simple object. Its methods transfer data between the browser and the server. This object is provided by JavaScript. The main purpose of this object is to modify the loaded page repeatedly.

The XMLHttpRequest object is the most important component of AJAX. AJAX cannot work without XMLHttpRequest object. The main feature of AJAX, updating elements without reloading the page, is implemented by XMLHttpRequest object.

All modern browsers support XMLHttpRequest object. Internet Explorer 5 and 6 use ActiveXObject. This object is also used for older versions of Internet Explorer. All other browsers have built-in support for XMLHttpRequest object.

Data can be processed in the form of XML, JSON (JavaScript Object Notation) and plain text by the XMLHttpRequest object. Therefore, AJAX is very reliable and widely used. This object also works with other protocols besides the HTTP protocol.

XMLHttpRequest Object Properties

The properties available with the XMLHttpRequest object are described below.

readyState

This property stores the current status of the XMLHttpRequest object. Status is defined by numbers from 0 to 4. Each number has a meaning. This status keeps changing during processing.

  • 0 - This status number indicates that the request has not been initialized yet.
  • 1 - This status indicates that the server connection has been established.
  • 2 - This status indicates that the request has been received.
  • 3 - This status indicates that the request is being processed.
  • 4 - This status indicates that the processing of the request has been completed and the response is ready to be sent.

onreadystatechange

This property of XMLHttpRequest object stores the name of the function which will be called every time the readyState changes.

responseText

This property returns the response data as a string. You can store its value in any normal JavaScript variable and display it.

responseXML

This property returns the response data as XML data.

status

This property returns the status. If the request is not successful, it will return 404 (NOT FOUND) status. If the request is successful, it will return 200 (OK).

statusText

This property returns the status as text. If the request is successful, OK will be returned, otherwise NOT FOUND will be returned as text.

XMLHttpRequest Methods

The methods available with XMLHttpRequest Object are given below.

open(method,URL,Async,UserName,Password)

This method is the most important method of XMLHttpRequest Object. Connection to server is established through this method. 5 parameters can be passed in this method. These are explained below.

  1. Method - With this parameter you define the method used to establish the connection. In this parameter you pass one value from GET or POST.
  2. URL - With this parameter the location of the file stored on the server is defined.
  3. Async - The value of this paramter is given in true and false. With this parameter you define whether the data is to be accessed synchronously or asynchronously.
  4. UserName - With this parameter you define the user name to establish the connection.
  5. password - With this parameter you define the password to establish the connection.

send(String)

This method is used to send the request to the server. This method is used in case of POST requests.

send()

This method is used to send a request to the server. This method is used in case of GET requests.

new XMLHttpRequest()

This method creates a new XMLHttpRequest object.

setRequestHeader()

This method adds a pair of label/value to the header to be sent.

getResponseHeader()

This method returns some specific header information.

getAllResponseHeaders()

This method returns complete header information.

abort()

This method cancels the current request.

Creating XMLHttpRequest Object

To create an XMLHttpRequest object, you use the new XMLHttpRequest() method. Its general syntax is given below.

var xhr = new XMLHttpRequest();

In the above syntax, xhr is a JavaScript variable that will store the XMLHttpRequest object. Creating an XMLHttpObject is explained with an example below.

var xmlHttp = new XMLHttpRequest();

If the browser is Internet Explorer 5 or 6, then you will create an XMLHttpObject as follows.

var = new ActiveXObject("Microsoft.XMLHTTP");

Introduction to AJAX Request

Just like the traditional web model, in AJAX also request is sent to the server and response is received. The only difference is that this process is performed by AJAX in the background without disturbing other page elements.

Request plays an important role in the working of AJAX. According to the request, it is decided whether the page elements will be loaded synchronously or asynchronously. Mostly the request is sent when an event is generated. For this, JavaScript and XMLHttpObject are used.

For example, the user has clicked on a link. Now the necessary information related to this link has to be obtained asynchronously from the server. In this situation, AJAX request will be sent.

The process of sending request to the server by AJAX is being described in the steps below.

First of all, the event generated from the user is handled by JavaScript.

For this, JavaScript calls a function.

In the function, XMLHttpRequest object is created by JavaScript.

Finally, to send the request to the server, the open() and send() methods of XMLHttpObject are called in the function.

Methods Used For AJAX Request

The methods of XMLHttpObject used to send data to the server are described below.

open()

This method is used to establish a connection with the server. This method is called on XMLHttpObject. 3 arguments are passed in this method. Its general syntax is given below.

xmlHttp.open(method, url, async);

  1. method - The first argument of the open() method is the method that you use to send data to the server. This method also tells the type of your request. For its argument, you define a value from GET or POST. You will be told about GET and POST later.
  2. url - The second argument is the url of the file that you want to load as a response.
  3. async - Through the third argument of open() method, you define whether you want to load the response synchronously or asynchronously. Hence, you define the value of this argument as true or false.

send()

This method is used to send the request. You call it on XMLHttpObject. The general syntax of this method is given below.

If you are establishing a connection to the server through GET method request, then you will use the syntax given below for this.

xmlHttp.send(); //For GET Request method

If you are establishing a connection to the server through POST method request, then you will use the syntax given below for this.

xmlHttp.send(string);

When you use POST request method, string is passed as argument in send method. This string is written in double quotes. It is written in the pair of name=value. This string is the value which is required to send data to the server. Such as username, password etc. Its example is given below.

xmlHttp.send("userName=dummy");

Types of AJAX Request

AJAX requests can be divided into 2 categories.

  1. Synchronous - When browser waits for the completion of the AJAX request before executing any other code, then you will send this type of request. For this type of request, the async parameter of the open() method is defined as false. This type of request is not recommended.
  2. Asynchronous - In this type of request, processing is done in the background, which is a feature of AJAX. For this type of request, the value of the async parameter of the open() method is defined as true. By default, AJAX requests are sent in asynchronous mode only.

These two types of AJAX requests are being explained below with examples.

Example

For asynchronous requests, you have to define a function. In this function, it is checked whether the response is ready by the server. Also, it is checked whether the status is ok or not. After this, the response of the server is displayed using DOM.

It is used to load the response asynchronously into the DOM. For this you use the responseText property of the XMLHttpRequest object. Its example is given below.


<html>
  <body>
    <button type="button" onclick="myFunction()">Click here</button>
    <p id="response"></p>
    <script type="text/javascript">
      function myFunction() {
        var xmlHttp = new XMLHttpRequest(); //Creating XMLHttpObject request

        xmlHttp.open("GET", "info-file.txt", true); //Open Method
        xmlHttp.send(); //Send method

        xmlHttp.onreadystatechange =
          function () //For detecting response ready state
          {
            if (this.readyState == 4 && this.status == 200) {
              //Checking ready state & request status
              document.getElementById("response").innerHTML = this.responseText; //Displaying response
            }
          };
      }
    </script>
  </body>
</html>

If the request is not asynchronous then you do not need to define a function. For this, you can display the response directly from the responseText property after the send method. Its example is given below.


<html>
  <body>
    <button type="button" onclick="myFunction()">Click Here</button>

    <p id="result"></p>

    <script type="text/javascript">
      function myFunction() {
        xmlHttp = new XMLHttpRequest();
        xmlHttp.open("GET", "info-file.txt", false);
        xmlHttp.send();
        document.getElementById("result").innerHTML = xmlHttp.responseText;
      }
    </script>
  </body>
</html>

Introduction to AJAX Server Response

In AJAX, the process of response from the server is different from the traditional web model. In the traditional model, the response is loaded directly in the web browser, whereas to get the AJAX response, you use properties like responseText and responseXML.

The AJAX response model provides several important advantages over the traditional web model.

Through AJAX, the response can be obtained without loading the entire web page.

Through AJAX, the response can also be obtained in JSON format.

Steps of AJAX Response

The process of AJAX response is being explained in the steps below.

If the request is asynchronous, then first of all a function is defined in the onreadystatechange property which will be called when the readyState changes.

Because the function defined in the onreadystatechange property will be called every time the status changes. Therefore, at the beginning of this function, it will be checked whether the readyState is 4? And whether the status is OK?

If the condition is true, the response is displayed using the responseText and responseXML properties along with the DOM. This object is used for this.

If the request is synchronous, then there is no need to create a function and check the condition.

In the case of a synchronous request, the response is displayed using the XMLHttpRequest object.

AJAX Server Response Properties

The properties used for AJAX server response are explained below.

responseText Property

This property is used to get the server's response as a string. If the request is asynchronous, then you will use it inside the function with the DOM in this way.

<html>
  <body>
    <p id="Response"></p>

    <script type="text/javascript">
      //Creating & sending request

      var xmlHttp = new XMLHttpRequest();
      xmlHttp.open("GET", "info.txt", true);
      xmlHttp.send();

      //End of request

      //Getting response

      xmlHttp.onreadystatechange = function () {
        if (readyState == 4 && status == 200) {
          //Checking for status
          document.getElementById("Response").innerHTML = this.responseText;
        }
      };

      //End of response
    </script>
  </body>
</html>


If the request is synchronous then you can use it directly like this:
<html>
  <body>
    <p id="Response"></p>

    <script type="text/javascript">
      //Creating & sending request
      var xmlHttp = new XMLHttpRequest();
      xmlHttp.open("GET", "info.txt", false);
      xmlHttp.send();
      //End of request

      //Getting response

      document.getElementById("Response").innerHTML =
        X - H - RObject.responseText;

      //End of response
    </script>
  </body>
</html>

responseXML Property

You use this property to get response from the server in the form of XML. The most important thing you should know about using this property is that this property returns an XML DOM object.

You display the information through this object only. The rest of the process is just like the responseText property. Its example is given below.


<html>
  <body>
    <p id="Response"></p>

    <script type="text/javascript">
      //Creating & sending request

      var xmlHttp = new XMLHttpRequest();
      xmlHttp.open("GET", "info.txt", true);
      xmlHttp.send();

      //End of request

      //Getting response

      xmlHttp.onreadystatechange = function () {
        if (readyState == 4 && status == 200) {
          var xmlDoc = xmlHttp.xmlResponse; //Getting XML object
          var res = xmlDoc.getElementByTagName("Name");
          var response = (document.getElementById("Response").innerHTML = res);
        }
      };

      //End of response
    </script>
  </body>
</html>


AJAX Server Response Methods

The methods used in AJAX server response are given below.

getResponseHeader() Method

This method returns specific header information from the server response. For example, you want to know when the last file that you are accessing from the server was modified.

In case of asynchronous requests, it is called with this object and in case of synchronous requests, it is called with XMLHttpRequest object.

Monday, July 17, 2023

ASP.NET Core Razor Page with JavaScript - Updates of Rows of a table using fetch API


Project
  • Open the Visual Studio. 
  • Create web project using ASP.NET Core Empty template.
  • Project name: EditRecordRP
  • Solution name: EditRecordRP
  • .NET Core version: 5.0
  • Add the AddRazorPages() into the IServiceCollection in Startup class.
  • Use MapRazorPages() as terminal middleware in Startup class.
Look at the below updated code in Startup class.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace EditRecordRP
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
            });
        }
    }
}

  • Add a New Folder and rename it Pages.
  • Add a Razor Page in Pages folder and name it Index. Two files are generated which are Index.cshtml and Index.cshtml.cs
Index.cshtml

@page
@model EditRecordRP.Pages.IndexModel
@{
}
<style>
    tr th {
        background-color: brown;
        color: white;
    }

    tr td {
        text-align: center;
        padding: 5px;
    }
</style>

<h2 style="text-align:center;color:darkblue">Edit Record using JavaScript</h2>
<form id="form1" method="post">
    <table border="1" style="width:50%; margin:auto;">
        <tr>
            <th width="30%">Action</th>
            <th>Data</th>
        </tr>
        <tr>
            <td>
                <a class="edit" href="javascript:">Edit</a>
            </td>
            <td>
                Ajeet
            </td>
        </tr>
        <tr>
            <td>
                <a class="edit" href="javascript:">Edit</a>
            </td>
            <td>
                Amrita
            </td>
        </tr>
        <tr id="hiddenTr" hidden>
            <td>
                <a id="update" href="javascript:">Update</a>|
                <a id="cancel" href="javascript:">Cancel</a>
            </td>
            <td>
                <input id="txtnew" name="txtnew" type="text" />
            </td>
        </tr>
    </table>
</form>


<script type="text/javascript">

    (function () {
        var anchrs = document.querySelectorAll('.edit');
        let oldValue;
        anchrs.forEach(x => {
            x.addEventListener('click', function (event) {
                const cur_tr = x.closest('tr');
                cur_tr.insertAdjacentHTML("beforebegin", hiddenTr.innerHTML);
                oldValue = cur_tr.cells[1].innerText.trim();
                cur_tr.hidden = true;
                const inputbox = document.getElementById('txtnew');
                inputbox.setAttribute('value', oldValue)

            })
        })
    })();

</script>

On clicking Edit link, we get links for Update and cancel. And the input box appears in the side cell to update the old value. We have to write the code for Update and Cancel. Update will be based on JavaScript fetch API. Update will post the form on the server using post method.

Index.cshtml.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace EditRecordRP.Pages
{
    public class IndexModel : PageModel
    {
        public JsonResult OnPost(string txtnew)
{ } } }


Friday, May 19, 2023

Origin of JavaScript and its History of Development

JavaScript was created in 1995 by a programmer named Brendan Eich for Netscape Communications Company. Brendan Eich worked in the same company and initially JavaScript was named LiveScript but to establish its market, it was renamed JavaScript after the famous programming language Java of that time to increase its market value.

It should be remembered that JavaScript and Java are not the same thing. JavaScript is a scripting language, on the other hand, Java is a full fledged general programming language. JavaScript was initially used only within web applications whereas Java can be used to build any type of applications. So there was no similarity between the two. Its name was changed to JavaScript in order to achieve success in marketing. Remember that era of 1995-2000 is remembered as browser war and all such efforts were made by the browser developing companies of that time to increase the market share so that it could become popular in the market. Even today, apart from some superficial similarities, JavaScript is not related to the Java programming language in any way.

After the release of JavaScript, more and more browsers started adding JavaScript support. Even so, JavaScript was not considered a serious programming language at the time. Its early releases were plagued by notable performance and security issues, but the developers had no choice. If they wanted to run the program in the browser, they had to use JavaScript.

A notable period in the history of JavaScript is 2008. In 2008, Google's creation of the open-source Chrome V8, a high-performance JavaScript engine, provided a turning point for JavaScript. The subsequent proliferation of faster JavaScript engines made it possible for developers to build sophisticated browser-based applications with performance that competed with desktop and mobile applications.
Soon after, Ryan Dahl released an open-source, cross-platform working ecosystem called Node.js. It provided a way to run JavaScript code from outside the browser. This freed JavaScript from browser limitations and directly led to the current popularity of JavaScript. Today, you can use JavaScript to write all kinds of applications, including browser, server, mobile, and desktop applications. Most major online companies today, including Facebook, Twitter, Netflix, and Google, use JavaScript in their products.

With the help of modern JavaScript, not only front end web applications can be created, but backend applications can also be created, apart from web applications it is possible to create desktop as well. Desktop applications are built with the help of the Electron framework of JavaScript. For example, Visual Studio Code has been built with the help of this framework.

Ajeet Kumar May 20, 2023

Hot Topics