Javascript — 7 useful concepts with example

Useful advanced concepts
May 3 2022 · 6 min read

Javascript has been a very popular language for a long time and is widely used around the community.

Here is a summary of some useful advanced concepts.

Let’s get started.


1. Hoisting

Hoisting means to pull something up, javascript also does the same.

JavaScript has a mechanism that moves all declarations of variables and functions to the top of their scope before code execution.

You can use var or function before declaring it. It’s useful when you know requirements, but don’t know that how to implement it?

Hoisting performs differently for var, let, and const.

For var

x = 5;
console.log(x); //outputs 5
var x;

It runs successfully and logs 5 as output as a declaration of x moved on top of that block.

Also, another example of var

console.log(x);   //outputs undefined

var x = 5;

It logs undefined as we have initialized (assigned a value) x at the time of declaration, that’s after printing its value.

For let and const

Hoisting performs the same in the case of let and const .

Consider the same example as var

// let
x = 5;
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x;


// const
console.log(x); // ReferenceError: Cannot access 'x' before initialization
const x = 5;

let and const are not declared or initialized before output, it gives a Reference Error like the above code.

For functions

Hoisting can be used for functions too

myFunc("John");

function myFunc(name) {
  console.log("My name is " + name);  //My name is John
}

2. var vs let vs const

We all are using var, let, and const to initialize variables in javascript commonly. Let’s know the difference between them.

Before the ES6 module, var was used everywhere to declare variables. But due to some cons of var , Javascript has defined another way that is let . And const are used to maintain constant values.

We can differentiate them in the following manners.

Scope

  • var have global(If they have declared globally) or functional(if they have declared inside functions) scope.
     
var x = "hello from x";  //globally scoped
    
function newFunction() {
    var y = "hello from y"; //scoped in function
}
  • let is block-scoped. Block means anything that resides in curly braces {} . It can be function or if condition or switch case.
let x = "hello from x";
let count = 3;

if (count > 2) {
    let x = "hello from x inside block";
    console.log(x);// "hello from x inside block"
}

console.log(x) // x is not defined
  • const is block-scoped same as let .We can define const as below
const x = "hello from x";

Declaration

  • var can be updated or redeclared like below
var x = "hello from x";
x = "hello from x again";

// or 

var x = "hello from x";
var x = "hello from x again";
  • let can be updated but not redeclared
let x = "hello from x";
x = "hello from x again";

// but not

let x = "hello from x";
let x = "hello from x again"; // error: Identifier 'x' has already been declared
  • const can not be updated or declared
const X= "HELLO FROM X"
X = "HELLO AGAIN"  //error: Assignment to constant variable.

// and

const X = "HELLO FROM X";
const X = "HELLO FROM X AGAIN"; // error: Identifier 'X' has already been declared

Use case to use let instead of var

Consider the following example using var

var x = "hello from x";
var count = 3;

if (count > 2) {
   var x = "hello from x inside condition"; 
}
    
console.log(x) // "hello from x inside condition"

In the above example, if you intentionally want to change the value of x , then there will be no issue with the code.

It becomes a problem when you are working with large code, and don’t know that var x has been already declared, it will cause lots of bugs in code.

here is the same example using let ,

let x = "hello from x";
let count = 3;

if (count > 2) {
   let x = "hello from x inside condition"; 
}
    
console.log(x) // "hello from x"

Since let is block-scoped, both variables are treated as different variables. For this reason let is a better choice than var if variables using let are not declared more than one time in the block.


3. Function Rest parameters

In a simple javascript function, we can add any number of parameters in the function definition if we know them.

function myFunc(var1, var2)

But if we don’t know the number of parameters for the functions, then we can use the rest parameters. They can be written by prefixing like below,

function sum(...args) {
  let sum = 0;
  for (let arg of args) {
    sum += arg;
  }
  return sum;
}


// can pass any number of arguments
sum(1,2,3);   //6
sum(1,2,3,4,5,6);  //21
sum(1,2,3,4,5,6,7,8,9,10);  //55

4. Closures

We know that variables are only accessible within scopes, but what if we want block-scoped variables outside that scope??

Closures are functions that are defined inside other functions and execute locally scoped variables and allow them to access outside of scope.

  • A basic example of closure,
function myFunc() { 
      let message = 'hello';
      
      function insideMyFunc() {
           console.log(message);
      }
      insideMyFunc();
}

myFunc();

The output will be hello in that case.

  • It can be written in other ways also,
function myFunc() { 
      let message = 'hello';
      
      function insideMyFunc() {
           console.log(message);
      }
      
      return insideMyFunc;
}

var myFunc1 = myFunc();
myFunc1();

In this case, you can not execute myFunc() directly as it returns insideMyFunc . You have to assign it to another var that is myFunc1 and can execute myFunc1() later.

output: hello
  • An advanced example of closure,
function myFunc(x) {
  
     function insideMyFunc(y) {
           console.log(x + " " + y);
     }
     return insideMyFunc;
}

var func1 = myFunc("Hi");
var func2 = myFunc("Hello");

func1("there");
func2("there");

myFunc takes Hi as x and returns insideMyFunc to func1. func1 takes there as yand finally prints Hi there .

The output will look like this,

output of func1 : Hi there
output of func2 : Hello there

5. Symbols

Symbols are used to define unique names even if they are the same.

let x = Symbol("id");
let y = Symbol("id");
console.log(x == y) //false

They are new primitive types like Number, String, and Boolean serving object properties. It is used to create a totally unique identifier.

Suppose you are using a third-party library that returns some random user object, and you want to add unique id on that object, but that should not be accessible outside of the object, then you can use Symbol .

Here is an example of using a symbol and the way it can be accessible,

let user = { name: "lorem" };  

let id = Symbol("id");  

user[id] = 1;  

console.log(JSON.stringify(user)); //{"name":"lorem"}
console.log(user);  //{ name: 'lorem', [Symbol(id)]: 1 }
console.log(user[id]);  // 1
console.log(user.id);  // undefined
console.log(Object.getOwnPropertyNames(user)) //[ 'name' ]

for (let key in user){
  console.log(key)  // name
}

You can explore more about symbols from this article.


6. Iterables and Iterators

Javascript defines two protocols iterables and iterators for iterations of data structure over for…of loop. Instead of for , for…of reduces the complexity of the indices when using nested loops.

iterables

Data structures like array, string and Sets have symbol.iterator() method. They are known as iterables.

const array = [1,2,3];

// or it can be written as for (let x of array){
for (let x of array[Symbol.iterator]()){   
    console.log(x);
}

The output of it should be,

1
2
3

iterators

They are objects returned by symbol.iterator() method.

They use next() method which returns the next item in the sequence. It contains mainly two properties,

  1. value: can be a value of the next item
  2. done: indicates whether iteration is completed or not
const array = [1,2,3];

let arrIterator = array[Symbol.iterator]();

console.log(arrIterator.next()); // {value: 1, done: false}
console.log(arrIterator.next()); // {value: 2, done: false}
console.log(arrIterator.next()); // {value: 3, done: false}
console.log(arrIterator.next()); // {value: undefined, done: true}

Above is the default iterator, but they also can be defined manually like below

function iterator(index = 0, end, step = 1) {
  const rangeIterator = {
     next() {  
         if (index < end) {
             let result = { value: index, done: false }
             index += step;
             return result;
         }
         return { value: undefined, done: true }
     }
  };
  return rangeIterator;
}

The example simply ranges over the index till the end increasing by step value. Once iteration will over, it will set done to true and will terminate the loop. It can be accessed as below

const it = iterator(1, 5, 1);

let result = it.next();

while (!result.done) {
 console.log(result.value); // 1 2 3 4
 result = it.next();
}

7. Generator functions

Generators return multiple values using yield . They conform iterators and iterables protocol, but unlike them, we don’t have to maintain the internal state of variables using generators.

Generator functions can be written using function*. They do not initially execute their code. Instead, they return a special type of iterator. When we call the generator’s built-in next() method, the Generator function executes until it encounters the yield keyword.

Here is an example of a generator function,


function* iterator(index = 0, end, step = 1) {
      while (index < end) {
        yield index;
        index += step;
      } 
}


// can call generator like below
const generator = iterator(1,5,1);

for (let value of generator) {
  console.log(value);
}

The output of it is,

1
2
3
4

That’s it for today. Hopefully, this will give you some interesting insights into Javascript variables, functions, and concepts. As always, feedback and suggestions are more than welcome, please add comments in the response section.


sumita-k image
Sumita Kevat
Sumita is an experienced software developer with 5+ years in web development. Proficient in front-end and back-end technologies for creating scalable and efficient web applications. Passionate about staying current with emerging technologies to deliver.


sumita-k image
Sumita Kevat
Sumita is an experienced software developer with 5+ years in web development. Proficient in front-end and back-end technologies for creating scalable and efficient web applications. Passionate about staying current with emerging technologies to deliver.

Whether you need...

  • *
    High-performing mobile apps
  • *
    Bulletproof cloud solutions
  • *
    Custom solutions for your business.
Bring us your toughest challenge and we'll show you the path to a sleek solution.
Talk To Our Experts
footer
Subscribe Here!
Follow us on
2024 Canopas Software LLP. All rights reserved.