Learn these 10 things to boost up your JavaScript as a webdev(part-01)
Rohit Roy
Posted on May 7, 2021
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
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
Head over to this link to learn more:
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.
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');
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
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.
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);
}
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 isruntime 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);
}
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;
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
}
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;
}
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;
}
There is a nice blog about coding style. Head over to it.
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 :
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);
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);
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
withundefined
or keeps them uninitialized in the case oflet
andconst
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 theconst
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
What if I pass just one argument?
function getSum(x, y) {
return x + y;
}
console.log(getSum(10)); // NaN ( as undefined + 10 )
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);
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);
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
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
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));
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 ]
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);
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));
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 calledarguments
which provides us all the passed arguments in a list sequence. But in the case ofarrow function
, there is nothing available by default.
Learn more about arrow function:
That's all for today. Hope you like this. Happy JavaScript learning.
Posted on May 7, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 28, 2024
November 27, 2024