DEV Community

Cover image for Learn these 10 things to boost up your JavaScript as a webdev(part-01)
Rohit Roy
Rohit Roy

Posted on • Edited on

Learn these 10 things to boost up your JavaScript as a webdev(part-01)

Grasping the whole things of 10 topics will be beneficial for beginners if you have started your journey to learn web development and JavaScript. These 10 topics are like fire ant, they are small in size but powerful. Let's begin.

1. Types and more types

When you code, it is pretty certain that you are going to work with some texts, numbers, boolean values. JavaScript has to deal with these different types of values to treat them differently. But JavaScript gives freedom to the programmers to assign any types of value to a variable. JavaScript does the whole thing of recognizing the type of the assigned value automatically under the hood, we don't need to care. Instead, we need to care when we start using these variables to do some calculations or may be modifications.

In JavaScript, we can divide the types into two different big names.

1. Primitive types 
    1. undefined
    2. Boolean
    3. String
    4. Number
    5. BigInt
    6. Symbol
2. Structural types 
    1. objects
    2. functions
Enter fullscreen mode Exit fullscreen mode

We can easily check the type of any value using typeof operator.

let foo = 45;
console.log(typeof foo); // number
foo = 'devto';
console.log(typeof foo); // string
foo = true;
console.log(typeof foo); // boolean
Enter fullscreen mode Exit fullscreen mode

Head over to this link to learn more:

Stack Data Structure

2. Event loop in JavaScript

Let's first learn some JavaScript related terms before get into it.

JavaScript Runtime

When we run a JavaScript code, it has to be executed at someplace. This place is called JavaScript Runtime. We sometimes call this a JavaScript engine that reads our code line by line(interpreter) and executes it. Let's say we are creating a web application using JavaScript, then we ought to run this code in a browser to see its output. Now chrome browser uses 'v8' as its JavaScript engine. On the other hand, Mozilla uses 'Spider Monkey' and Internet Explorer uses 'Chakra'. So the engine could be different for the browsers. That means the way they handle our code could be slightly different though they follow the same standard.

Learn more about runtime : JavaScript Engine

Stack data structure

The stack data structure is mainly used to run every function in the JavaScript code. It is named stack because its working principle is similar to many real-world things like a deck of cards. The working principle of the stack is simple. When we call a function, a frame of all the associated data of the function call gets pushed onto the stack. This data represents all local variables of the function, its arguments etc.

Let's say inside the function, we invoke another function. If we do so, the second function frame will be pushed to a stack which will be at the top. Therefore at any time, JavaScript will only execute the top function or process in the stack. That's why we call JavaScript a 'single-threaded programming language.

represent the LIFO principle by using push and pop operation

Learn more about stack: Stack Data Structure

Now, where is the event loop here? Ok, wait!

Async callbacks

Let's run this code.

function callback() {
    console.log('now');
}
console.log('Before waiting');
setTimeout(callback, 5000);
console.log('After waiting');
Enter fullscreen mode Exit fullscreen mode

We have used setTimeout method of the global window object. If we run this we will get

Before waiting // immediately
After waiting // immediately 
now // after a minimum of 5 seconds
Enter fullscreen mode Exit fullscreen mode

We have passed a callback function to the setTimout method. So it executes this function after a minimum of 5 seconds. But JavaScript didn't wait for its execution. Instead, it jumps over to the next line and executes it. Now how does this work?

Head over to this great tool Loupe created by Philip Roberts. You can also watch his great talk at JSConf.

Then click Save + Run button to simulate the process. At the right of the screen, you will see a block named Web Apis which control the browser provided methods like this one(setTimeout).

Here when the JavaScript engine reaches the setTimeout line, it gives the responsibility to run this code to the Web APIs of the browser. In the meantime, JavaScript finishes the processes at the stack. When 5 seconds finishes, The frame in the Web Apis is moved to another block called Callback queue. And in this block, another data structure named queue is used. There is a difference regarding push and pop between stack and queue.

In a stack, LIFO(Last-in-first-out) principle and in queue, FIFO(First-In-First-Out) principle is followed at the time of pushing and popping any objects.

img

This piece of information is important to know when there are multiple objects in the callback queue which can happen when we use setTimeout multiple times.

After our stack become empty, it is time to activate the event loop. Firstly event loop checks if the stack is empty or not and there is any object in the queue. If the stack becomes empty, the event loop pop the object( using FIFO method) and pushes it into the stack and then the callback function executes and we get our output.

3. try...catch: Let's catch errors

Errors are everywhere. To put it bluntly, every developer is 'bugfinder' and 'bugsolver'. Normally if there is any bug in our JavaScript code, the whole program stops executing, it stops immediately! And we get a fancy error message after that. Now let's see how this happens and how we can control this behaviour of JavaScript to hesitate before stopping straight away and instead of showing fancy messages we could show some modified message to the users so that they can confirm what went wrong.

To do this, we will use a construct try...catch to catch errors and instead of stopping the whole thing, we will do something reasonable.

Let's run this code

try{
  console.log(foo);
}
catch(err){
  console.log(err.message);
}
Enter fullscreen mode Exit fullscreen mode

This will print in the console: foo is no defined.

So when any errors that JavaScript can catch take place, it uses some built-in objects like Error, SyntaxError, ReferenceError, TypeError etc. to save the information about the error. Each of these objects has three properties

This construct only can catch runtime errors. Hence they are unable to catch parsetime errors.

When we write a code and runs it in the engine, at first JavaScript engine reads the code and then executes the code. If there is an error that occurs in the reading time or parsing time, it is called parsetime error and for the other, it is runtime error.

Till now, we only have used default error messages to show useful warnings. What if we can show our custom messages to debug the code more easily. We can do this using the throw operator. At this point, we can use this throw operator to throw errors at a certain condition to control the error handling as our wish. Let's throw an error object with a custom error message at a certain condition. We have to just create a new instance of any error object provided by JavaScript and pass the message as an argument.

try...catch can only catch errors that can be detected by the JavaScript engine by default. But sometimes we don't want to continue the program at a certain point or condition which is unknown to the engine. This could be handled easily by using the throw operator.

let student = '{ "name": "Dorothy"}'; // incomplete data

try {

    let user = JSON.parse(student); // <-- no errors

    if (!student.age) {
        throw new SyntaxError("Student age not found!"); // (*)
    }

} catch (err) {
    console.log("Error: " + err.message);
}
Enter fullscreen mode Exit fullscreen mode

4. A good coding style: way to conquer

At the time of working with a team, it is necessary to follow a particular coding style for all of its members. It increases the flow of detecting bug and reviewing code. It must be irritating to review a single code file without any comments and no maintenance of the same space or tab size on every statement. Hence it is always a good practice to follow a standard coding style. Let's see some of the standard rules of JavaScript coding.

Curly Braces

Writing conditional statements is the most common type of statement in programming. For a long code, we should specify the block or scope using curly braces, it helps to understand where scope starts and ends. It also reduces making mistakes.

But for a shorter code, we can write this on the same line to make it cleaner.

if(num % 2 == 0){
    console.log("Num is even");
}
if(num) return true;
Enter fullscreen mode Exit fullscreen mode

Indents

Indenting makes code beautiful and readable. The developer is divided over the size of the horizontal indents. Some prefer 2 and others 4 spaces. However, 4 spaces is the most popular one.

let him = "him";
if(him === him){
    console.log("He is him"); // 4 spaces as horizontal indents
}
Enter fullscreen mode Exit fullscreen mode

Here is another type of indentation which is not so popular among beginners, vertical indentation. This type of indentation is used to divide many lines of code into logical blocks. Hence it helps to understand the logic and flow of the code. It is suggested to insert a new line after each logical block.

function getNumbers(x, y){
    let start = 1;
    let sum = 0;
    // newline
    for(let i = start; i < x ; i++){
        sum+= y * i;
    }
    // newline
    return sum;
}
Enter fullscreen mode Exit fullscreen mode

Functions

Some developer like to place all the functions at the top of the file, others prefer to put them at last. Though the last one is mostly used and preferable.

let num = giveNum();
let isEven = isEven(num);


function giveNum(){
    return Math.ceil(Math.random() * 6);
}

function isEven(num){
    return num%2 == 0;
}
Enter fullscreen mode Exit fullscreen mode

There is a nice blog about coding style. Head over to it.

coding-style

5. Caching: Make things faster

On a website, there are different types of data. We access some data frequently or commonly. Let's say there is a page that shows us user profile information if the user logged in. Now mainly this page's data is connected to the user database where the server matches the user with the existing list, get the information and then show them in the UI. Now if we allow our program to do this process when the user enters this page, the page will load continuously and when it gets the data, it will stop loading. This will make the user annoy for sure as it is increasing the loading time. So what we can do instead? Here comes the concept of caching. It refers to store the commonly or frequently accessed data to storage, and then upon requesting this data from the user, getting the data from the storage. Hence we have to request to the server only once. This process makes the data loading much faster, hence enhances the user experience.

There are two types of caching, such as client caching and server caching.

Client caching

Client caching means keeping the commonly accessed data locally or into the user machine. For example, we can save all the useful information to the local storage of the machine so that when the user requests any information, the data transfer happens between this machine and the website which is less costly and fast.

Server caching

This can be achieved by saving a local copy of commonly requested data on the server. So when the user requests the same information again, at first the server checks for the local copy. If it gets the copy, it will send the data over any API.

Learn more about caching :

Balancing client and server-caching in web application development

6. Cross browser testing: Reach more people

There are hundreds of browsers out there. Hence people don't only use chrome or firefox. They could use any of them. So every website should work in most of the browsers. The way a developer tests the availability of his web application is called cross-browser testing.

It is just a fancy of saying "Make your application to work in most of the browsers". This cross browsers testing includes another thing that is to support any devices provided with additional accessories like people with disabilities use browsers with some additional technological support like screenreaders, AI-based support device etc.

Now there might arise a question: Why do we have to take this responsibility or why our content will not work on all other devices?

All the browsers don't use the same technology, though they follow the same standard. When we create content, at first we have to take a look if this content is accessible in most browsers. In other words, if these particular browsers support this content. Hence supporting is a big issue in web development. You may create a nice 3D animation in the web browser using fancy CSS and JavaScript at the time of development, but it will not get support in older browsers as they don't support some new features of JavaScript. A developer always has to be cautious about this kind of issue to make his content more accessible to more people.

Learn more about cross-browser testing :

Cross-browser testing

7. Block bindings: things just get easy

When we declare any variable in C-based language, the variable is declared and created at the same time. But in JavaScript, things get pretty overwhelmed( ! ). After introducing ECMAScript6, things get easier to handle now.

Before ECMAScript6, we only have to use var to declare any variable. This one option let us create some erroneous code. Let's see how :

function getInfo(roll) {
    if (roll === 43) {
        console.log(newStudent); // undefined
        var newStudent = "Namileu";
        console.log(newStudent); // Namileu
    }
    else {
        console.log(newStudent); // undefined
    }
}

getInfo(44);
Enter fullscreen mode Exit fullscreen mode

We are creating newStudent variable inside an if block using var declaration, but it is still accessible from its else block that returns us undefined. How is that possible?

When the JavaScript engine gets our code, firstly it reads the code and saves some pieces of information and references that will be useful throughout the execution process. When it gets a variable declaration using var it saves it in the memory and initialized with undefined by default ( even though we initialize our variable with a value ).

But in the case of let and const, it doesn't initialize them, just stores them. Now after finishing this pre-execution part, the JavaScript engine starts executing the code. When executing, when the engine sees we have initialized it with the new value, it also initializes the variable with this new value. That's the reason we can access the newStudnet variable from another scope or even before initializing the variable. We'll get undefined in all odd cases here( default value ). Let's see now what happens for let and const.

function getInfo(roll) {
    if (roll === 43) {
        console.log(newStudent); // Cannot access 'newStudent' before initialization
        let newStudent = "Namileu";
        console.log(newStudent); // Namileu
    }
    else {
        console.log(newStudent); // Cannot access 'newStudent' before initialization
    }
}

getInfo(44);
Enter fullscreen mode Exit fullscreen mode

As the declarations using these two remain uninitialized, we can't access them before they are initialized at the run-time.

This pre-execution process when the engine stores variables and initialize them if it is declared with var with undefined or keeps them uninitialized in the case of let and const is called hoisting.

If you notice carefully, you'll see we get something like block-level controls over variables created with let and const as they can't be accessed from another block or scope. That makes our life easier than ever. So we don't even bother about var which gives us undefined before initialization that could make our code vulnerable.

It is good practice to use let with such variables that have a possibility of absorbing new values throughout the program. And for constant variables ( these are not going to be changed throughout the program ), use the const keyword.

8. Default parameters

In JavaScript, all the parameters of a function get initialized with undefined by default. But sometimes it is useful to give them a value to be initialized with. Let's see an example :

function getSum(x, y) {
    return x + y;
}
console.log(getSum(10, 45)); // 55
Enter fullscreen mode Exit fullscreen mode

What if I pass just one argument?

function getSum(x, y) {
    return x + y;
}
console.log(getSum(10)); // NaN ( as undefined + 10 )
Enter fullscreen mode Exit fullscreen mode

Now if we set a default value of y to 0, then if we provide a value in arguments, JavaScript will use the passed value instead. But if we pass undefined or don't pass anything, it will use the default value.

Another important fact to remember that all default arguments are evaluated at call time. What does that mean?

It means that each time we call a function, the parameters of a function are created ( fresh copy ). So these variables don't exist after control has passed the scope. Let's see an example :

function getArraySum(x, arr = []) {
    let sum = 0;

    arr.push(x);

    for (let i = 0; i < arr.length; i++) {
        console.log(arr.length); // 1, 1, 1
        console.log(arr[i]); // 4, 5, 10
    }
}
getArraySum(4);
getArraySum(5);
getArraySum(10);
Enter fullscreen mode Exit fullscreen mode

Here we are calling getArraySum function three times. In each time, the size of the array is 1.

Sometimes we want to make the user pass an argument to a particular function. In other words, we want to make an argument mandatory. We can achieve this by using the throw operator and just the characteristic of a default parameter

function isEmpty() {
    throw new Error("Please provide a value for this argument!");
}

function getArraySum(x = isEmpty(), arr = []) {
    let sum = 0;

    arr.push(x);

    for (let i = 0; i < arr.length; i++) {
        console.log(arr.length);
        console.log(arr[i]);
    }
}
getArraySum(); // Please provide a value for this argument!
getArraySum(5);
getArraySum(10);
Enter fullscreen mode Exit fullscreen mode

9. Spread operator and rest operator

Let's start with an example:

function getSum(x, y) {
    console.log(arr);
    return x + y;
}
console.log(getSum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); // 3
Enter fullscreen mode Exit fullscreen mode

We passed more arguments needed for the function. Hence only the first two numbers will be used for the function body. All other numbers will be ignored. But how can we use all other arguments for doing useful something?

We can use the rest operator. This will gather all arguments into an array. The syntax for the rest operator is ...(three dots).

function getSum(...all) {
    let sum = 0;
    for(let i = 0; i < all.length ; i++){
        sum += all[i];
    }
    return sum;
}
console.log(getSum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); // 55
Enter fullscreen mode Exit fullscreen mode

Then what is the spread operator?

The spread operator is the opposite thing of the rest operator with the same syntax ( ! ). So it expands an array and object.

let arrOfNumbers = [2, 3, 4];
console.log(Math.max(...arrOfNumbers));
Enter fullscreen mode Exit fullscreen mode

So this syntax could be used to merge two arrays or objects:

let arr1 = [1, 2, 3, 4, 5];
let arr2 = [6, 7, 8, 9, 10];
let arr3 = [...arr1, ...arr2]; // [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] 
Enter fullscreen mode Exit fullscreen mode

10. Arrow function

We have used function expressions many times in the examples used beforehand. But this is not the only way to define any function. Arrow function is an alternative to function expression. It is compact in structure. Let's see an example :

const about = {
    name: 'Mr. Nekolus amster',
    age: 34,
    profession: 'Software Development',
    street: '4817 Thompson Street',
    city: 'Paramount',
    State: 'California',
    Country: 'US'
}
const printDetails = (details) => {
    for (let property in details) {
        console.log(`${property}: ${details[property]}`);
        /*
        name: Mr. Nekolus amster
        age: 34
        profession: Software Development
        street: 4817 Thompson Street
        city: Paramount
        State: California
        Country: US
        */
    }

}
printDetails(aboutMe);
Enter fullscreen mode Exit fullscreen mode

We treat arrow functions like variables. Let's return data instead of printing them.

...
const printDetails = (details) => {
    for (let property in details) {
        if(property === "profession"){
            return details[property]; // returns "Software Development"
        }
    }

}
console.log(printDetails(aboutMe));
Enter fullscreen mode Exit fullscreen mode

However, the arrow function doesn't provide us with many features provided by function expression. For example:

  • function expression can't be used as a constructor function.
  • In function expression, we had an access to a special object called arguments which provides us all the passed arguments in a list sequence. But in the case of arrow function, there is nothing available by default.

Learn more about arrow function:

MDN-Arrow function

That's all for today. Hope you like this. Happy JavaScript learning.

Top comments (0)