Blog

  • JavaScript – Package Manager

    In JavaScript, a package manager is a tool that makes simple to install, manage, and update libraries, or packages, in your project. You can save time and add functionality without having to start from scratch by using these packages, which are reusable code pieces provided by other developers.

    Need of a Package Manager

    Suppose there were no package managers. The following duties were likely to be completed by hand in that condition −

    • Find all of the packages that are suitable for your project.
    • Verify that the packages do not include any known vulnerabilities.
    • Pick up the packages.
    • Place them where they belong.
    • Keep an eye out for any developments on each of your packages.
    • Update all packages if a new release takes place.
    • Get rid of any packages that are unnecessary.

    It takes a lot of effort and time to manually arrange tens or even hundreds of things. The two most common package managers in JavaScript are as follows −

    Node Package Manager (npm)

    Node Package Manager, or NPM, is a platform that makes it easier for developers to use and share JavaScript code. It is used with Node.js, a JavaScript runtime that makes JavaScript work not only on a browser but also on a server.

    This is what NPM does −

    • NPM makes it simple to add, modify, and remove code parts known as packages. These packages work similarly to the building blocks that programmers use to add specific features to their applications, including managing user input or connecting to a database.
    • Using commands in the terminal, developers may quickly set up or modify code with NPM (for example, npm install to add a package).
    • NPM offers millions of packages that people from all around the world contribute to, so if you need code for a common task, someone has undoubtedly already created a package for it.
    • Many packages are interdependent. NPM keeps an eye on those links and ensures that you have all the resources needed for the code to run.

    Commands

    Here are some of the commands that you can use to take the benefits of NPM −

    • npm install “package-name”: Using this commands you can install a package.
    • npm uninstall “package-name”: By this command you are able to remove a package.
    • npm update “package-name”: Using this command you can update a package.
    • npm init: By this command you can set up a new project and create a package.json file.

    The package.json file

    Every JavaScript project, whether Node.js or a browser application, can be scoped as a npm package that includes its own package information and package.json file is used to describe the project.

    When npm init is used to start a JavaScript/Node.js project, package.json is created with the following basic metadata provided by developers −

    • name: the name of your JavaScript library/project
    • version: It shows the version of your project. This field is often ignored in application development because there looks to be no need for versioning open-source libraries. But it can be used as a source for the deployment’s version.
    • description: The project’s description.
    • license: The project’s license

    Yarn

    Yarn, like NPM, is a platform that allows developers to manage code packages. Facebook created it to address certain problems that developers experienced with NPM, like performance and stability.

    The installation method is divided into three steps −

    • Resolution: Yarn begins resolving dependencies by sending queries to the registry and iteratively looking for each dependency.
    • Fetching: Next, Yarn checks a global cache directory to see if the required package has been downloaded. If it has not already, Yarn gets the package’s tarball and saves it in the global cache so it can work offline and avoid downloading dependencies several times. Tarballs containing dependencies can also be placed in source control for full offline installations.
    • Linking: Finally, Yarn connects everything together by copying all of the required files from the global cache to the local node_modules directory.

    Commands

    Here are some of the commands you can use for using yarn −

    • yarn add “package-name”: You can use this command for installing a package.
    • yarn remove “package-name”: You can use this command for removing a package.
    • yarn upgrade “package-name”: Use this command to update a package.
    • yarn init: You can set up a new project and create a package.json file.

    Yarn uses a lock file (yarn.lock) to verify that all developers on your team are using the same version of packages. This helps to avoid bugs caused by version variations.

    Why Use a Package Manager?

    Both npm and Yarn are widely used, and the decision between the two is frequently based on personal or project preferences. Here are the reasons why you should use package manager −

    • Save time: It saves time by easily installing and utilizing existing libraries.
    • Dependency Management: Automatically manage libraries that your chosen libraries require.
    • Easy Updates: When upgrades or security updates are available, packages can be updated rapidly.
  • JavaScript – Mutability vs Immutability

    If you are a web developer you have seen the terms mutable and immutable objects in JavaScript. But what these words mean, and why do they matter? This section will help you understand.

    • What mutable and immutable objects are
    • The main differences between them
    • How to make and change them
    • The benefits and drawbacks of using each type in your code

    This knowledge is very helpful for writing cleaner, safer, and more reliable JavaScript code.

    Mutable Objects

    Mutable objects in JavaScript are ones that can be changed after they are created, including arrays, objects, functions, and dates. To add, removeor modify values in these objects, use bracket notation (object[“property”]) or dot notation (object.property).

    But, changing these objects can sometimes lead to problems: it can unintentionally affect other parts of your code, make debugging more difficult, and use more memory. Because of this, even if you can directly change mutable objects, it is usually better to avoid doing so to keep your code simpler and more reliable.

    A mutable data type allows you to change it. Mutability lets you change existing values without creating new ones.

    For each object a pointer is added to the stack, pointing to the object in the heap. Consider the following code −

    const student ={
       name:"Aarav",
       age:15,
       hobbies:["drawing","playing guitar","cycling"]};

    On the stack, you will see student, which is a pointer to the actual object on the heap.

    const student2 = student;
    console.log(student);
    console.log(student2);

    When student is assigned to student2, an additional pointer is added to the stack. Now, these pointers are pointing to a single item on the heap.

    Reference data copies pointers rather than values.

    student2.age =25;
    console.log(student);
    console.log(student2);

    Changing the age of student2 affects the age of the student object. You know it is because they both point to the same thing.

    Clone Object Properties

    To clone the properties of an object, use the Object.assign() function with the spread operator. These allow you to update the attributes of the cloned object while keeping the original object’s properties unchanged.

    How Object.assign() Function Works

    The object.assign method replicates properties from one object (the source) to another (the target), returning the updated target object.

    Here is the syntax −

     Object.assign(target, source)

    The method takes two arguments: target and source. The target is the object that receives the new attributes, whereas the source is where the properties originate. The target may be an empty object {}.

    When the source and target have the same key, the source object overwrites the value of the key on the target.

    const student ={
       name:"Aarav",
       age:15,
       hobbies:["drawing","playing guitar","cycling"]}const student2 = Object.assign({}, student);

    The properties of the student object were copied into an empty target.

    student2 now owns its own properties. You can show this by modifying the values of any of its characteristics. Making this adjustment will have no effect on the student object’s property values.

    student2.age =25;
    console.log(student);
    console.log(student2);

    The value of student2.age, which was modified to 25, has no bearing on the value of student.age because they both have separate attributes.

    Immutable Objects

    Immutable objects are those that cannot be modified after it has been created. Strings, numbers, booleans, nulls, and undefined are all immutable in JavaScript. You can not alter their values or characteristics directly.

    Rather, you have to create a new object with the changes that are required. For example, you can combine two strings or add two integers, but this will result in a new string or number that does not change the original ones.

    Immutable objects offer several advantages over mutable ones. They can reduce side effects, make your code easier to understand and maintain, and boost performance.

    Creating Immutable Objects

    There are several methods to build immutable objects in JavaScript. One option is to use the Object.freeze() method which blocks changes to an existing object. For example- if you freeze an array or object and then attempt to edit it you will receive an error or have no effect.

    Another option is to use the const keyword which creates a constant variable that cannot be reassigned. For example- if you declare a string or an integer as const and then try to reassign it, you will receive an error. But const just makes the variable immutable not the object it refers to.

    Let us consider an example −

    const num =46;const newNum = num;

    By looking at the code above, num has been reassigned to newNum. Both num and newNum now have the same value: 46. Changing the value on newNum does not affect the value on num.

    let student1 ="Aarti";let student2 = student1;

    The code above creates a variable called student1 and assigns it to student2.

    student1 ="Saurabh"
    console.log(student1);
    console.log(student2);

    Changing student1 to Saurabh does not affect student2’s initial value. This shows that in primitive data types, actual values are duplicated, so each has its own. Student1 and student2 have distinct stack memory addresses.

    The stack follows the Last-In, First-Out principle. The first thing to enter the stack is the last to leave, and vice versa. Accessing objects saved in the stack is simple.

    Modifying Immutable Objects

    Immutable objects cannot be changed directly, so you have to use other techniques to edit them. One option is to use the spread operator (…), which duplicates the properties or elements of an object or array into a new one. For example, you can use the spread operator to generate a new array with a new item or a new object with a new attribute without changing the originals.

    Another option is to use the Object.assign() method, which transfers the properties of one or more source objects to a target object. For example, you can use Object.assign() to create a new object that inherits the properties of two existing objects without modifying them.

    Using the Spread Operator

    For arrays: Assume you have an array named fruits −

    const fruits =["apple","banana","orange"];

    For creating a new array using an additional item without modifying or altering fruits −

    const newFruits =[...fruits,"grape"];
    console.log(newFruits);// Original array is unchanged
    console.log(fruits);

    Here is the outcome of the above code −

    [ 'apple', 'banana', 'orange', 'grape' ]
    [ 'apple', 'banana', 'orange' ]
    

    For Objects: Let us say you have an object called person −

    const person ={ name:"Maya", age:30};

    For creating a new object with an additional attribute (for example- country) without modifying the person −

    const newPerson ={...person, country:"India"};
    console.log(newPerson);// Original object is unchanged
    console.log(person);

    Following is the output of the above code −

    { name: 'Maya', age: 30, country: 'India' }
    { name: 'Maya', age: 30 }
    

    Using Object.assign()

    For Objects: Object.assign() creates a new object by combining the properties from multiple objects. Assume you have two objects: person and additionalInfo.

    const person ={ name:"Maya", age:30};const additionalInfo ={ country:"India", hobby:"reading"};

    For creating a new object using the properties from both person and additionalInfo −

    const newPerson = Object.assign({}, person, additionalInfo);
    console.log(newPerson);// Original object is unchanged
    console.log(person);

    Here is the output of the following code −

    { name: "Maya", age: 30, country: "India", hobby: "reading" }
    { name: "Maya", age: 30 } 
    

    Benefits of Immutability

    Immutability can have several advantages for your web development projects −

    • One of them is to avoid side effects which are changes in your program’s state or behavior that you did not want or determine.
    • For example- if you send a mutable object as an argument to a function, the function may change the object, affecting other sections of your code that depend on it.
    • But if you supply an immutable object the function cannot change it, allowing you to avoid this problem. Another benefit is improved performance, particularly in frameworks that use a virtual DOM, like React.
    • A virtual DOM is a replica of the real DOM that is updated in memory and then compared to the actual DOM to apply the changes.
    • If you use immutable objects the comparison can be faster and more efficient because you just need to check the reference rather than the value.

    Drawbacks of Immutability

    Immutability can have various disadvantages, which you should be aware of −

    • One of them is to increase memory consumption as you must build new objects every time you wish to change them.
    • This can also have an impact on trash collection which is the process of cleaning up memory by removing unneeded items.
    • For example- if you generate a large number of temporary objects in a loop, you risk overloading memory and slowing trash collection.
    • Another disadvantage is that creating and modifying immutable objects requires the use of additional methods or operators, making your code more verbose and difficult to read.
    • To get the same outcome you may need to write more lines of code or utilize layered spread operators.

    Mutability vs Immutability

    Here is the basic difference between mutability vs immutability in the tabular form −

    AspectMutabilityImmutability
    MeaningYou can change the value after creation.Once created, the value cannot be changed.
    ExampleArrays or objects (e.g., let numbers = [1, 2, 3];’)Strings or numbers (e.g., ‘const name = “Amit”;’)
    Can you change it?Yes, you can change or modify it.No, you cannot change it directly.
    How to change?You modify the original value.You create a new value instead of changing the original.
    Example code (change)‘numbers.push(4);’‘const newName = name + ” Deepak”;’
  • JavaScript – Minifying JS

    JavaScript enables dynamic and interactive features on websites and web apps. It is a key component of modern web development. But as JavaScript files grow larger and more complex, they can significantly affect page load times and overall speed.

    To solve this issue, developers use techniques like code minification to make JavaScript code simpler without compromising functionality.

    What is the “Code Minification”?

    Minimization is another name for minification. Code minification is the process of optimizing code to minimize bandwidth use, save space, and speed up page loads.

    All of the fundamental programming languages, like HTML, CSS, and JavaScript provide code minification. The procedure is not immediate, though. Making code more concise without sacrificing functionality requires some effort.

    JavaScript code must be parsed, compressed and the output obtained in order to minify it. It should be nearly impossible to read with the naked eye once it has been minified. Everything that once made the code readable has been eliminated, including extraneous white spaces, comments, and newline characters.

    It may be necessary to make other code changes, including rewriting local variables, using implicit conditionals, removing block delimiters or inlining methods.

    Need for Minimizing the Code

    Here are the showing the need for minimizing the code in JavaScript −

    • Faster Load Times: Minified code reduces file size which leads to faster download and execution times, ultimately improving the user experience.
    • Bandwidth optimization: Smaller file sizes limit the amount of data exchanged between the server and the client resulting in lower bandwidth and hosting costs.
    • Improved SEO: Search engines like faster-loading pages, which can result in higher search engine rankings and more organic traffic to the website.
    • Enhanced User Experience: Reduced load times boost user engagement and satisfaction while decreasing bounce rates and increasing conversions.

    Un-minified vs Minified JavaScript Code

    Let’s look at some sample code below. The first block contains common, un-minified JavaScript −

    // Program to check if a word is a palindromefunctionisPalindrome(word){// find the length of the wordconst length = word.length;// loop through half of the wordfor(let i =0; i < length /2; i++){// check if first and last characters are the sameif(word[i]!== word[length -1- i]){return'This is not a palindrome';}}return'This is a palindrome';}// take inputconst inputWord ="hello";// call the functionconst result =isPalindrome(inputWord);
    console.log(result);

    Output

    This will generate the below result −

    This is not a palindrome
    

    Now we will see how the same code will look once it has been minified. See the minified version below −

    functionisPalindrome(w){const l=w.length;for(let i=0;i<l/2;i++)if(w[i]!==w[l-1-i])return"This is not a palindrome";return"This is a palindrome"}const inputWord="hello",result=isPalindrome(inputWord);console.log(result);

    As you can see, the second piece of code is significantly smaller and more concise. That means it will load and render faster, reducing page load time and boosting content.

    We have reduced 529 bytes to 324 bytes, gained 205 bytes of free space, and cut page load time by over 40%.

    How to minify JavaScript Code

    You can minify JavaScript code in a variety of ways. Each of these methods takes a different strategy from the others.

    It is nearly impossible to manually minify all of the code in large JavaScript files. Manually minifying JavaScript files is only feasible for small files owing to the time involved.

    To begin the manual JavaScript minification process, open your JavaScript file in your choice text editor and manually delete each space one at a time. It will take a few minutes to clean up all of the gaps and comments in the JavaScript file. Some of these text editors may even support regular expressions, probably speeding up the process significantly.

    The other option is to install minification software on your computer and run it from the command line. You would need to choose the file you want to minify and provide it in the command line switch with the destination file. The remaining tasks would be handled by the minifying tool.

    Code Minification Vs Compression

    While both code minification and compression work to minimize file size, they vary in their approach and purpose −

    • Code Minification: Code minification includes removing unnecessary characters from source code in order to improve readability and load times while maintaining functionality.
    • Compression: Techniques for reducing file size by encoding data more efficiently, which often result in irreversible changes to the file structure. Gzip, Brotli, and deflate are common compression techniques used in network transmission to reduce bandwidth usage.
  • JavaScript – Memoization

    As our systems grow and start doing more complex calculations, the need for speed grows and process optimization becomes necessary. Ignoring this issue results in applications that use a lot of system resources and operate slowly.

    In this chapter, we will discuss memoization, a technique that can significantly reduce processing time when used properly.

    What is Memoization?

    Memorization is a technique for speeding up applications by storing the results of expensive function calls and providing them when the same inputs are used again.

    Let’s try to understand this by dividing the term into smaller parts −

    • Expensive Function Calls: In computer applications, memory and time are the two primary resources. So a function call that uses a lot of these two resources because it is performing a lot of calculations is considered expensive.
    • Cache: A cache is only a short-term data storage system that holds information to allow faster processing of future requests for that information.

    Benefits of Memoization

    After receiving input, a function does the necessary computation, caches the result, and then returns the value. If the same input is received again in the future, the process will not need to be repeated. It would just return the response that was saved in memory. As a result, a code’s execution time will be greatly reduced.

    When to Use Memoization?

    Here are some of the points mentioned while you should use memoization −

    • When a function calls itself. For example, consider the recursive functions.
    • When the function is pure (returns the same value every time it is invoked). If the value changes with each function call, there is no reason for holding it. As a result, we cannot use memoization in JavaScript when the function is impure.
    • When the function has a high temporal complexity. In this case, keeping the results in a cache improves efficiency by reducing time complexity by avoiding re-computation of functions.

    Memoization in JavaScript

    JavaScript memorization is an optimization technique used to minimize the application’s runtime, complexity, and proper use of time and memory. The procedure involves reducing the number of expensive function calls (a function that recursively calls itself and has some overlapping issues) by using an additional space (cache).

    We store the values that were computed in those previous subproblems using memoization. The saved value is then used once again if the identical subproblem comes up, which lowers the time complexity by reducing the need to perform the same calculation repeatedly.

    How Does Memoization Work?

    JavaScript Memoization purely based on two below concepts −

    • Closure
    • High-order function

    Closures

    The Closure is made up of a function enclosed by references to the state. A closure provides access to an outside function’s scope from an inside function. The closure is formed in JavaScript when a function is created.

    let greeting ="Welcome";functionwelcomeMessage(){let user ="Rahul"; 
       console.log(`${greeting} to the program, ${user}!`);}welcomeMessage();

    Output

    This will generate the below result −

    Welcome to the program, Rahul!
    

    In the above JavaScript code −

    • The variable greeting is a global variable. It can be accessible from anywhere, including the welcomeMessage() function.
    • The variable user is a local variable that can only be used within the welcomeMessage() function.

    Lexical scoping allows for nested scopes, with the inner function having access to the variables specified in the outer scope. Hence, in the code below, the inner function welcome() gets access to the variable user.

    functionwelcomeMessage(){let user ="Rahul";functionwelcome(){
          console.log(`Greetings, ${user}!`);}welcome();}welcomeMessage();

    Output

    This will procedure the following output −

    Greetings Rahul!
    

    Now we will modify the welcomeMessage() function and rather than invoking the function welcome(), we will return the welcome() function object.

    functionwelcomeMessage(){let user ='Rahul';functionwelcome(){
          console.log(`Greetings ${user}!`);}return welcome;}let greet =welcomeMessage();greet();

    Output

    If we run this code, we will get the same results as before. But it is important to note that a local variable is often only present during the function’s execution.

    This means that after welcomeMessage() is executed, the user variable is no longer available. In this case, when we call gree(), the reference to welcome() remains, as does the user variable. A closure is a function that keeps the outside scope in the inside scope.

    Greetings Rahul!
    

    Higher-Order Functions

    Higher-order functions act on other functions by passing them as arguments or returning them. In the code above, welcomeMessage() is an example of a higher-order function.

    Now, using the well-known Fibonacci sequence, we will look at how memoization uses these concepts.

    Fibonacci sequence: The Fibonacci sequence is a set of numbers that begin and end with one, with the rule that each number (known as a Fibonacci number) is equal to the sum of the two numbers preceding it.

    1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...
    

    So a simple recursive function for this problem will be as follows −

    functionfibonacciSeq(n){if(n <2)return1;returnfibonacciSeq(n -1)+fibonacciSeq(n -2);}

    If we plot the recursion tree for the above function at n=4, it will look like this. As you can see, there are too many unnecessary computations. Let’s try to fix this via memoization.

    functionmemoizedFibSeq(num, memo){// Initialize memo array if not provided
       memo = memo ||[1,1];// if num is less than or equal to 1, return the result directlyif(num <=1)return memo[num];// If result is already computed, return it from memoif(memo[num])return memo[num];// Calculate and store the result in memo
       memo[num]=memoizedFibSeq(num -1, memo)+memoizedFibSeq(num -2, memo);return memo[num];}// Calculate the 10th Fibonacci number
    console.log(memoizedFibSeq(10));

    Output

    Here is the outcome of the above code −

    89
    

    We modify the function in the code example above to accept an optional input named memo. We use the cache object as a temporary memory to store Fibonacci numbers and their corresponding indices as keys, which can then be retrieved later in the execution.

  • JavaScript – Local Storage

    This chapter will show you how to use JavaScript’s localStorage to save data for several browser sessions. We will demonstrate how to use this method using the Window.localStorage property, as well as go over the principles of web storage in JavaScript.

    What is localStorage in JavaScript?

    The localStorage feature allows JavaScript apps and websites to save key-value pairs in a web browser with no expiration date. This means that the stored data remains even if the user closes the browser or restarts the computer.

    LocalStorage is a window object property, so it can interact with and manipulate the browser window. It can also work when combined with other window settings and methods.

    Syntax

    The below Syntax returns a storage object and it can be used to get the current origin’s local storage space.

    myStorage = window.localStorage;

    What is Window.localStorage?

    The localStorage method is accessible via the Window.localStorage property. Window.localStorage is a JavaScript Window interface component that represents a window with a DOM content within.

    The Window interface has a wide number of functions, constructors, objects and namespaces. Window.localStorage is a read-only property that returns a reference to a local storage object which is intended to store data that can only be accessed by the origin that created it.

    When to use localStorage

    In simple terms, localStorage securely stores and retrieves data. While localStorage can save small amounts of data, it is not suitable for large datasets. Because localStorage is accessible to anybody who uses the device, you should avoid keeping critical information there. You can use it to save user preferences like language or theme. If you use it regularly it can also serve as a data cache. LocalStorage can save form data so that it is not lost when the user closes the browser.

    If your application requires you to log in, you can use localStorage to store your session data. You can stay logged in even after closing and reopening the browser.

    How does localStorage work?

    You have heard it before: localStorage stores data. And, if you’re saving data, you might need to access it later. In this section, we will look at exactly how localStorage works. Here’s an overview of how it works −

    • setItem() It adds a key and value to localStorage.
    • getItem() It retrieves/gets things from local storage.
    • removeItem(): It removes an item from localStorage.
    • clear(): To erase all data from localStorage, use clear().
    • key(): To obtain a localStorage’s key, it passes a number.

    Usage of setItem() Method

    The setItem() method lets you store values in localStorage. It accepts two parameters: a key and a value. The key can be used later to get the value linked to it. Here is how it should look −

    localStorage.setItem('name','Ankit Sharma');

    In the code above, the key is name, and the value is Ankit Sharma. As we said before, localStorage can only store strings. To store arrays or objects in localStorage you have to first convert them to strings.

    To do this, we will use the JSON.stringify() method before providing to setItem(), as follows −

    const userArr =["Ankit",25]
    localStorage.setItem('user',JSON.stringify(userArr));

    Usage of getItem() Method

    The getItem() method gives you access to the data saved in the browser’s localStorage object. This method takes a single parameter, the key, and returns the value as a string −

    localStorage.getItem('name');

    This returns a string with the value “Ankit Sharma”. If the key given is not found in localStorage, it will return null. For arrays, we use the JSON.parse() function, which converts a JSON string in a JavaScript object −

    JSON.parse(localStorage.getItem('user'));

    Using the array we constructed previously, here’s how to access it from local storage −

    const userData =JSON.parse(localStorage.getItem('user'));
    console.log(userData);

    This method returns the array [“Ankit”, 25]. You can look into the webpage and find it in the console, as follows −

    [Log] Name from localStorage: - "Ankit Sharma" (example.html, line 22)
    [Log] User array from localStorage: - ["Ankit", 25] (2) (example.html, line 26)
    

    This output is from Safari so it will look a little different on other browsers. Let us compare it with a different array which is not stored with localStorage −

    const userArr2 =["Anjali",27];
    console.log(userArr2);

    So now we have two arrays on the console you can see in the below output −

    [Log] Name from localStorage: - "Ankit Sharma" (example.html, line 22)
    [Log] User array from localStorage: - ["Ankit", 25] (2) (example.html, line 26)
    [Log] ["Anjali", 27] (2) (example.html, line 29)
    

    Normally, if you comment them out in the code editor they should disappear from the terminal. But anything saved via localStorage stays. Here is one example.

    Usage of removeItem() Method

    To delete an item from localStorage you can use the removeItem() function. When a key name is given to the removeItem() method so the current key is deleted from storage. If no object is linked with the given key this method will do nothing. Here’s the code.

    .localStorage.removeItem('name');

    Usage of clear() Method

    To delete all things from localStorage you can use the clear() function. When this method is used so it will clear all records in the domain’s storage. It does not accept any parameters. Use the following code −

    localStorage.clear();

    Usage of key() Method

    The key() function is useful for looping over keys while giving a number or index to localStorage to get the key’s name. The index option gives the key’s zero-based index for which you want to retrieve the name. Below is how it looks −

    localStorage.key(index);

    Advantages of LocalStorage

    Here are some advantages of using localStorage −

    • The first advantage of localStorage is that saved data never expires.
    • You can still access the data offline since localStorage stores data that is available even without an internet connection.
    • LocalStorage is more secure than cookies and provides greater control over your data.
    • LocalStorage provides more storage capacity than cookies.
    • Cookies can only store four kilobytes of data, whereas local storage can contain up to five megabytes.

    Disadvantages of LocalStorage

    Here are some disadvantages of localStorage −

    • LocalStorage is synchronous which refers to each operation occurs one after the other.
    • This has little impact on smaller datasets but as your data grows it can become a significant concern.
    • Local storage is more secure than cookies, but it should not be used to store sensitive information.
    • Anyone with access to the user’s device can view the data stored in localStorage.
    • Also localStorage can only save strings; if you want to store other data types, you must first convert them to strings.
    • Finally, storing too much data in localStorage may cause your application to slow down.
  • JavaScript – Lexical Scope

    What is Lexical Scope?

    Lexical scope refers to an expression’s definition area. In other words, an item’s lexical scope is the context in which it was generated.

    Lexical scope is sometimes known as static scope. The lexical scope of an item is not always determined by where it was invoked (or called). The lexical scope of an object serves as its definition space.

    So you may know that variables and methods have different levels of scope −

    • Global Scope: Variables defined outside of any function or block yet accessible throughout the program.
    • Local Scope: Variables defined within a function or block that can only be accessed within that function or block are considered local scope.
    • Nested Scope: Inner functions can access variables in their parent functions.
    • Block Scope: Variables defined with let and const are only valid in the block where they are declared, such as loops or conditionals.

    Now let us see some examples of lexical scope in JavaScript in the below section.

    Example 1

    Let us see the example code below −

    // Define a variable in the global scopeconst myName ="Shwetaa";// Call myName variable from a functionfunctiongetName(){return myName;}

    In the above sample code, we defined the myName variable in the global scope and used it in the getName() function.

    So here question arises, Which of the two spaces covers myName’s lexical scope? Is it the global or local scope of the getName() function?

    So you have to remember that lexical scope refers to definition space, not invocation space. As a result of our definition of myName in the global environment, its lexical scope is global.

    Example 2

    Let us see another example of lexical scope in JavaScript −

    functiongetName(){const myName ="Swati";return myName;}

    So here question arises, Where is myName’s lexical scope?

    And the answer is, Notice how we defined and invoked myName within getName(). As a result, myName’s lexical scope is the local environment of getName(), which is myName’s definition space.

    How Does Lexical Scope Work?

    The code that can access a JavaScript expression is determined by the environment in which it was defined.

    In other words, only code in an item’s lexical scope has access to it. For example, take the following code −

    // Define a functionfunctionmyLastName(){const lastName ="Sharma";return lastName;}// Define another functionfunctionshowFullName(){const fullName ="Swati "+ lastName;return fullName;}// Invoke showFullName():
    console.log(showFullName());

    Output

    The calling above will return −

    Uncaught ReferenceError: lastName is not defined
    

    Notice that the previous snippet’s call to showFullName() resulted in an Uncaught ReferenceError. The error was returned because the item can only be accessed by code within its lexical scope.

    As a result, the showFullName() function and its internal code cannot access the lastName variable because it was defined in a different scope. In other words, lastName’s lexical scope differs from that of showFullName().

    LastName’s definition space is showLastName(), whereas showFullName()’s lexical scope is the global environment.

    Now, see this below code −

    functionshowLastName(){const lastName ="Sharma";return lastName;}// Define another function:functiondisplayFullName(){const fullName ="Swati "+showLastName();return fullName;}// Invoke displayFullName():
    console.log(displayFullName());
    displayFullName;

    This will generate the below result −

    Swati Sharma
    

    Because showFullName() and showLastName() are in the same lexical scope, they both returned “Swati Sharma” in the example above.

    In other words, because the two procedures are written in the same global scope, showFullName() might call showLastName().

    Summary

    Understanding lexical scope in JavaScript is important for creating clean, maintainable code. By properly scoping variables and functionsyou canminimize naming conflicts, improve code readability, and prevent undesirable effects. Understanding lexical scope leads to more ordered and efficient programs.

  • JavaScript – Kaboom.js

    Kaboom.js makes it easy to create JavaScript games. You can add physics, detect collisions and make sprites in addition to controlling different scenes. By using Kaboom.js, you can focus on making an engaging and creative game instead of writing complex code. Think about adding other features like backgrounds, power-ups or scoring to further enhance your game!

    Getting Started with Kaboom

    To start your Kaboom application you need to call Kaboom to initialize the Kaboom contexts −

    kaboom({
       global:true,});

    If you build your application in your code editor, be careful to import both your JS file and the Kaboom.JS library into your HTML file.

    <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Simple Kaboom Game</title><script src="https://kaboomjs.com/lib/0.5.0/kaboom.js"></script></head><body><script src="example.js"></script></body></html>

    Create your Scene

    In Kaboom, everything is a component of a scenario. The scenario is essentially how the game will look, behave, and play out.

    kaboom({
       global:true,});scene("main",()=>{//...}]);

    In the example above, the scene method is activated for our “main” scene, and the other game elements are given inside the function. Lastly, we need to call the scene by using start at the end.

    Load your Sprites and Create Player

    Now we will have to start “drawing” our sprites onto our game UI. A sprite is a two-dimensional bitmap contained in a larger scene, usually in a 2D video game. For this chapter, we will use a Yeti sprite grabbed from Imgur.

    To load our sprites and build our players, we will use the load sprite method, enter our sprite image information and then create the player in the scene.In the previous example, we call the scene method for our “main” scene and pass the remaining game pieces to the function. Finally, we must use “start at the end” to refer to the scenario.

    kaboom({
      global:true,});loadRoot('https://i.imgur.com/');loadSprite('yeti','OqVwAm6.png');scene('main',()=>{const yeti =add([sprite('yeti'),pos(80,80),color(255,188,0),]);});start('main');

    If your code is accurate, you should see a yeti sprite on screen. Right-click your index.html file, copy the path, and paste it into a new browser page.

    Output

    This will generate the below result −

    Kaboom Example

    We’ll begin by adding the body component to your initialized sprite. This method effectively forces your sprite to follow the “rules of gravity”. Once this method is run, your sprite will begin to slide off the screen, therefore we will have to create a temporary platform as well.

    kaboom({
      global:true,});loadRoot('https://i.imgur.com/');loadSprite('yeti','OqVwAm6.png');scene('main',()=>{const yeti =add([sprite('yeti'),pos(80,80),color(255,188,0),body(),]);// Add the groundadd([rect(width(),12),pos(0,280),origin('topleft'),solid(),]);});start('main');

    Output

    This will produce the following result −

    Kaboom Example

    Kaboom Key Events

    The body method allows your sprite to use methods like and . We can use these methods alongside with key events to provide additional interesting behavior to our sprite. Let us give our Yeti the capacity to move left and right and jump. Add the following lines of code in your main scene function.

    kaboom({
      global:true,});loadRoot('https://i.imgur.com/');loadSprite('yeti','OqVwAm6.png');scene('main',()=>{const yeti =add([sprite('yeti'),pos(80,80),color(255,188,0),body(),]);// Add the groundadd([rect(width(),12),pos(0,280),origin('topleft'),solid(),]);// Add controls for jump and moveconstJUMP_FORCE=320;constMOVE_SPEED=120;keyPress("space",()=>{
        yeti.jump(JUMP_FORCE);});keyDown("left",()=>{
        yeti.move(-MOVE_SPEED,0);});keyDown("right",()=>{
        yeti.move(MOVE_SPEED,0);});});start('main');

    Output

    This will generate the following outcome −

    Kaboom Example

    Add a Background Image

    To conclude this chapter of Kaboom, we will add a background image to our UI and resize it to fit.

    kaboom({
       global:true,});loadSprite("yeti","https://i.imgur.com/OqVwAm6.png");loadSprite("bg","/Users/abc/Downloads/image.jpg");scene("main",()=>{// Add background spriteadd([sprite("bg"),scale(width()/240,height()/240),// Adjust the size of the backgroundorigin("topleft"),]);const yeti =add([sprite("yeti"),pos(80,80),color(255,188,0),body(),]);// Add the groundadd([rect(width(),12),pos(0,280),origin("topleft"),solid(),]);// Controls for jump and movementconstJUMP_FORCE=320;constMOVE_SPEED=120;keyPress("space",()=>{
          yeti.jump(JUMP_FORCE);});keyDown("left",()=>{
          yeti.move(-MOVE_SPEED,0);});keyDown("right",()=>{
          yeti.move(MOVE_SPEED,0);});});start("main");

    Output

    This will lead to the following outcome −

    Kaboom Example
  • JavaScript – Immutability

    Immutable means that something that cannot be changed. In programming, immutable means a value that cannot be changed once set.

    Most programs require the generation, modification, and deletion of data. So, why would anyone want to deal with immutable data?

    In this tutorial, we will look at the immutability of primitives, arrays, and objects using JavaScript examples.

    Concept of Immutability

    Immutability is a simple but powerful concept. In simple terms, something that cannot be modified is an immutable value. We can come across situations when we need to create a new object in our code with a new attribute or value while maintaining the existing value, particularly when creating our apps. The idea of immutability allows us to create new objects without changing the original value.

    JavaScript has two types: primitive and reference. Primitive types consist of numbers, strings, booleans, null, and undefined. Reference types are objects, arrays, and functions.

    The difference between the two is that primitive types are immutable (unchangeable), whereas reference types are mutable (changeable). For example, a string is immutable:

    let userAge ="22";let userNewAge = userAge;
    userAge ="24";

    We simply generated two variables and used userAge to the userNewAge variable. But when we modify the value of userAge, you will realize that both remain the same.

    console.log(userAge === userNewAge);// false

    Why use Immutability?

    Here are some reasons that shows you should use immutability in Javascript −

    • Predictability: When the data does not change it is easy to understand how your software works.
    • Prevent bugs: Immutable data can help prevent unexpected changes that can cause program errors.
    • Simple to Share: As immutable data never changes so it is better to distribute it throughout your applications.

    Examples of Immutability

    Below are some example to show the immutability in JavaScript −

    Example 1

    Here is the first example using strings as you may know strings in JavaScript are immutable. When you change a string so you create a new one.

    // Create a string herelet greeting ="Hello, world!";// This will not change the original string.
    greeting[0]="h"; 
    
    console.log(greeting);

    Output

    In this example we are trying to change the first letter of the greeting from “H” to “h.” But strings cannot be edited in this way. The original string remains the same.

    Hello, world!
    

    Example 2

    Now we will talk about the second example, in which we will use arrays and you may know arrays are mutable but we can create a new array instead of changing the existing one with the help of the spread operator in Javascript.

    // create an arraylet numbers =[1,2,3];// Create a new array with an extra number.let newNumbers =[...numbers,4]; 
    
    console.log(numbers); 
    console.log(newNumbers);

    Output

    In the above example we started with an array of numbers instead of changing the numbers we created a new array called newNumbers and insert a new number. Check the below output −

    [1, 2, 3]
    [1, 2, 3, 4]
    

    Example

    Objects are also mutable but we can create a new object instead of changing the existing one.

    let person ={ name:"Amit", age:25};// Create a new object with an updated age.let updatedPerson ={...person, age:26}; 
    
    console.log(person); 
    console.log(updatedPerson);

    Output

    This will generate the below result −

    { name: "Amit", age: 25 }
    { name: "Amit", age: 26 }
    

    Importance of Immutability

    There are several reasons why immutability is so important to our everyday code.

    • Once set, an immutable value cannot be changed. Instead, a fresh value is created. So the value remains consistent and dependable throughout the code. As a result, it makes state management across the program easier. Plus immutability is a core principle of state management frameworks like Redux.
    • Code becomes easier to read and less prone to errors when data structures are not changed quickly. This helps with troubleshooting and maintenance.
    • Immutability encourages less side effects and more predictable code, which aligns with the ideas of functional programming.
  • JavaScript – Function Composition

    Function composition is a powerful functional programming approach that allows programmers to combine numerous functions into a single function. This compositional method enhances readability, modularity and code reuse. The compose function is important for JavaScript’s ability to provide function composition.

    What is Function Composition?

    The method of combining several functions to create a new function is known as function composition. The output of one function becomes the input of the subsequent function in the composition chain, involving an order of operations or transformations performed to an input value.

    After receiving two or more functions, the compose function creates a new function that applies the functions in a right to left order. It means that the function on the right is applied first, then the function on the left, and so forth.

    Example

    Let’s consider an example to get a better understanding of function composition. Now look at the three functions increaseBy5, tripleValue, and reduceBy10. We want to create a composite function that uses these functions to a given input value. To do that, use the compose function as follows −

    constincreaseBy5=(num)=> num +5;consttripleValue=(num)=> num *3;constreduceBy10=(num)=> num -10;const applyOperations =compose(reduceBy10, tripleValue, increaseBy5);const finalResult =applyOperations(7);
    
    console.log("The final result after applying the operations is:", finalResult);

    Three basic functions are defined in the above example: reduceBy10, tripleValue, and increaseBy5. In order to apply these functions to an input value of 7, we have to create a composite function. By linking the functions together in the right order, the compose function enables us to do this.

    TripleValue, increaseBy5, and reduceBy10 are all represented by the composite function applyOperations. The functions are applied in the given order when we call applyOperations with the input value 7, yielding the output value 36.

    Implement the Compose Function

    To take advantage of the power of function composition, we need to define the compose function. Here is the implementation −

    constcompose=(...ops)=>{return(value)=>{return ops.reduceRight((result, operation)=>{returnoperation(result);}, value);};};
    console.log("Chained functions have been successfully executed.");

    Output

    This will produce the following result −

    Chained functions have been successfully executed.
    The final result after applying the operations is: 26
    

    This implementation uses the spread operator…functions to allow the compose function to take any number of functions as arguments. It returns a new function that applies each function on the accumulated result by iterating over the functions in reverse order using reduceRight.

    Benefits of Function Composition

    When creating clear and maintainable code, function composition has the following advantages −

    • Re-usability: We can create large operations without duplicating code by assembling smaller, reusable functions. By allowing each function focus on a particular task, code modularity and re-usability are encouraged.
    • Readability: We can express complex operations in a more easy and concise way by using function composition. We can define the desired transformation in a manner that closely resembles the issue domain by chaining functions together.
    • Maintainability: Understanding, testing, and modifying individual functions is made simpler by the clear purpose of each function. Code that is easier to maintain and understand results from changes made to one function that have no effect on other functions in the composition.

    Summary

    One effective functional programming technique that promotes code modularity, reusability, and readability is function composition. By simply chaining several functions together and applying them to input values, the compose function allows us to write more expressive and maintainable code.

  • JavaScript – Execution Context

    We will learn about the JavaScript execution context in this chapter, where we will also cover its types, definition, execution stack, creation process, and overall execution phase. We will go over each topic individually. First, let’s get started with the introduction.

    What is Execution Context?

    The execution context is a term that describes the internal workings of code. The JavaScript Execution Context describes the environment in which JavaScript code can be run. The execution context specifies which code sections have access to the functions, variables and objects used in the code.

    During the execution context, the given code is parsed line by line, with variables and functions kept in memory. An execution context is similar to a container for storing variables; code is evaluated and then executed. So, the execution context provides an environment in which specific code can be executed.

    Types of Execution Context

    The JavaScript execution context types are as follows −

    • Global Execution Context/GEC
    • Functional Execution Context/FEC
    • Eval Execution Context

    Now let us discuss each type one by one in the below section −

    Global Execution Context

    GEC (Global Execution Context) is often referred to as the base or default execution. Any JavaScript code that does not occur in a function will be found in the global execution context. The word ‘default execution context’ refers to the fact that the code is executed when the file is first loaded into the web browser. GEC carries out the following two tasks −

    • First, it creates a global object for Node.js and a window object for browsers.
    • Second, use the keyword ‘this’ to refer to the Windows object.
    • Create a memory heap to store variable and function references.
    • Then it stores all function declarations in the memory heap and initializes all variables in the GEC with ‘undefined’.

    Because the JS engine is single-threaded, there is only one global environment that may be used to execute JavaScript code.

    Functional Execution Context

    FEC, or Functional Execution Code, is the type of context generated by the JavaScript engine when a function call is found. Because each function has its own execution context, the FEC, unlike the GEC, can have multiple instances. Also, the FEC has access to the whole GEC code, while the GEC does not have access to all of the FEC’s code. During GEC code execution, a function call is initiated, and when the JS engine finds it, it generates a new FEC for that function.

    Eval Function Execution Context

    Any JavaScript code executed using the eval function creates and retains its own execution context. But JavaScript developers do not use the eval function which is a component of the Execution Context.

    Phases of the Execution Context in JS

    There are 2 main phases of JavaScript execution context −

    • Creation Phase: In the creation phase, the JavaScript engine establishes the execution context and configures the script’s environment. It sets the values of variables and functions as well as the execution context’s scope chain.
    • Execution Phase: In this phase, the JavaScript engine runs the code in the execution context. It parses any statements or expressions in the script and evaluates any function calls.

    Everything in JavaScript works within this execution context. It is divided into two parts. One is memory and the other one is code. It is important to keep in mind that these phases and components are applicable to both global and functional execution settings.

    Creation Phase

    Let us see the below example −

    var n =6;functionsquare(n){var ans = n * n;return ans;}var sqr1 =square(n);var sqr2 =square(8);  
    
    console.log(sqr1)
    console.log(sqr2)

    Output

    This will generate the below result −

    36
    64
    

    Initially, the JavaScript engine executes the full source code, creates a global execution context and then performs the following actions −

    • Creates a global object that is a window in the browser and global in Node.js.
    • Creates a memory for storing variables and functions.
    • Stores variables with undefined values and function references.

    After the creation phase the execution context will be moved to the code execution phase.

    Execution Phase

    During this step, it begins running over the entire code line by line from top to bottom. When it finds n = 5, it assigns the value 5 to the memory variable ‘n’. Initially, the value of ‘n’ was undefined by default.

    Then we get to the ‘square’ function. Because the function has been allocated memory, it goes right to the line var square1 = square(n);. square() is then invoked, and JavaScript creates a new function execution context.

    When the calculation is finished, it assigns the value of square to the previously undefined ‘ans’ variable. The function will return its value and the function execution context will be removed.

    The value generated by square() will be assigned to square1. This also applies to square two. Once all of the code has been executed, the global context will look like this and will be erased.

    Execution Stack

    The JavaScript engine uses a call stack to keep track of all contexts, both global and functional. A call stack is also referred to as a Execution Context Stack, Runtime Stack or Machine Stack.

    It follows the LIFO concept (Last-In-First-Out). When the engine initially starts processing the script, it generates a global context and pushes it to the stack. When a function is invoked, the JS engine constructs a function stack context, moves it to the top of the call stack and begins executing it.

    When the current function completes the JavaScript engine removes the context from the call stack and returns it to its parent. Let us check the below example code −

    functionfirstFunc(m,n){return m * n;}functionsecondFunc(m,n){returnfirstFunc(m,n);}functiongetResult(num1, num2){returnsecondFunc(num1, num2)}var res =getResult(6,7);
    console.log("The result is:", res);

    Output

    This will produce the below result −

    The result is: 42
    

    In this case, the JS engine creates a global execution context and starts the creation process.

    It initially allocates memory for firstFunc, secondFunc, the getResult function, and the res variable. Then it invokes getResult(), which is pushed to the call stack.

    Then getResult() calls secondFunc(). At this point, secondFunc’s context will be saved to the top of the stack. Then it will begin execution and invoke another function, firstFunc(). Similarly function A’s context will be pushed.

    After execution of each function it is removed from the call stack.

    The call stack’s size is determined by the operating system or browser. If the number of contexts exceeds the limit a stack overflow error will be returned. This happens when a recursive function has a base condition.

    functiondisplay(){display();}display();

    Output

    This will generate the below result −

    C:\Users\abc\Desktop\Javascript\example.js:2
        display();
        ^
    RangeError: Maximum call stack size exceeded
    

    Summary

    Finally, understanding how JavaScript works behind the scenes needs knowledge of the execution context. It defines the environment in which code is executed as well as the variables and functions available for use.

    The method of building involves creating the global and function execution contexts, the scope chain and allocating memory for the variables and functions. During the execution step the JavaScript engine goes over the code line by line. This includes evaluating and executing statements.