How to use call(), apply(), bind() in JavaScript?

In JavaScript objects have their own properties and methods. With every function we have three methods: call(), apply() and bind().

Before moving into this concept, first lets have a recap on this in functions. This keyword determines how a function is called (runtime binding).

There is a feature in JavaScript which allows to use the methods of some other objects to another object without redefining them. This way of borrowing is done through call(), apply(), bind() methods.

Call(), apply(), and bind() methods are used to set the this keyword independent of function call. Useful in callbacks.

Call():

Call method sets the this inside function and immediately executes the function. Here you can pass arguments as a list.

Syntax:

function.call(thisArg, arg1, arg2, …)

function – function that needs to be invoked with different this object.

thisArg – value that needs to be replaced with this keyword present inside this function.

arg1,arg2,… – arguments passed for invoking function with this.

Example:
 function test(arg1, arg2){
   console.log(this.num, arg1, arg2); // 100, 10, 20
}

test.call({num: 100}, 10, 20);
Output:

100,10,20

apply()

apply() method binds the this value to the function and executes the function. Here  you can pass argument as an array.

Syntax:
function.apply(this, [argumentsArray])

It returns the result of the function which is invoked by this.

function test(...args){
  console.log(this.num, args);//100, [1,2,3]
}
test.apply({num: 100}, [1,2,3]);
Output:

100, [1,2,3]

Bind()

Bind() function binds this value to the function and returns new function. We need to invoke the returned function separately.

Syntax:
function.bind(this,arg1,arg2,arg3,...)

Bind returns a copy of function with this and arguments.

function test(arg){

 console.log(this.number, arg);

}

let bindedFn = test.bind({number: 1}, "Abaython");

bindedFn();
Output:

1 Abaython

Differences : call() vs apply() vs bind()

call()apply()bind()
DefinitionCall method is a predefined javascript method. With call an object can use a method belonging to another object. Here we supply list of argumentsSimilar to call(). But here we supply array of argumentsBind() helps in creating another function and execute later with new this function
ExecutionAt time of bindingAt time of bindingAt time when we execute the return function
Return?Yes it returns and calls the same function at time of bindingYes it returns and calls the same function at time of bindingYes it returns a new function of copy of function which can be used later.
ParameterList of argumentsArray of argumentsArray and any number of arguments

Key points to note:

  • call: binds the this value, invokes the function, and allows you to pass a list of arguments.
  • apply: binds the this value, invokes the function, and allows you to pass arguments as an array.
  • bind: binds the this value, returns a new function, and allows you to pass in a list of arguments.

Understanding rest and spread operator

ES6 has some great features that makes working with parameters and arrays easy. JavaScript uses three dots ( … ) for both the rest and spread operators. The main difference between these two operators is that rest operator collects a set of elements and stores them into a single array and spread operator expands an array of elements into a list of individual elements.

Spread operator:

Spread operator expands the values in an iterable like array or strings across zero or more arguments or elements. It is used to split up array of elements and object properties. Using spread operator we can combine two arrays more easily.

const arr1 = ['a','b','c'];
const arr2 = ['d','e','f'];
const combine = [ ...arr1, ...arr2];//spread operator
console.log(combine);
Output:

[ ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’ ]

When using spread, we are expanding a single variable into more.

Spread in function call:
function sum(n1,n2)
{
    console.log(n1+n2);
}
let arr=[10,20];
sum(...arr);//spread in function call
Output:

30

As you can see spread operator takes parameters and spreads them across arguments in function call.

What will happen if we have to work with unknown number of parameters?

Answer is using rest operator.

Rest operator:

It’s a collection of remaining elements. Useful for merging functional arguments into an array. We can use when we don’t know how many functional arguments are passed to our method.

const find_greater= (...args) => {

  console.log(args); /* lets see what's in args */

  return console.log(args.filter((x) => x > 25))

}

find_greater(25,36,42,12,17,9,58);
Output:

[25,36,42,12,17,9,58]

[36,42,58]

Another example,
function sum(first, ...others){

  for(let i=0; i<others.length; i++)

    first+=others[i];

  return first;

}

console.log(sum(12,14,22,15,9,7));

let [c,...rest] = [12,14,22,15,9,7];

console.log(...rest);

console.log(c);
Output:

79

14 22 15 9 7

12

Rest parameter have to be at the last because it collects all the remaining parameters into an array.

Rest is a collector. It collects the remaining elements.

Rest vs Spread Operator:
RestSpread
Rest operator allows us to pass an indefinite number of arguments to function by accumulating these several values into an array. Spread operator spreads or expands the values in an array or a string across one or more arguments.
The spread operator in JavaScript expands values in arrays and strings into individual elementsThe rest operator puts the values of user-specified data into a JavaScript array

Arrow function in JavaScript

Arrow functions expression is an alternative to traditional function expression. They are similar to lambda functions in python. These functions are often used in passing a function as a parameter to higher order functions. It is one of the features introduced in ES6.

The function ,

// function expression
let x = function(x, y) {
   return x * y;
}

Can be written as

// using arrow functions
let x = (x, y) => x * y;
Syntax:
let myFunction = (arg1, arg2, ...argN) => {
    statement(s)
}

myFunction – name of function

arg1,arg2,…argN – arguments of function

statement(s) – function body

Example:

The below example illustrates arrow functions with

  • No arguments
  • Single argument
  • Function expression
  • Function body
No arguments:
// with no argument
let noarg = () => console.log('Abaython');
noarg(); // Abaython
One argument:
// with one argument

let onearg = x => console.log(x);

onearg('Abaython'); // Abaython
As Expression:
//as expression
let num = 50;
let func = (num > 20) ?
  () => console.log('Greater than 20') :
  () => console.log('Less than 20');
func(); // Greater than 20
Function Body:
let sum = (a, b) => {

    let result = a + b;

    return result;

}

let result1 = sum(10,20);

console.log(result1); // 30
Output:

Abaython

Abaython

Greater than 20

30

Arrow functions and this keyword:

In a regular function this keyword refers to the function where it is called. But arrow functions does not have this and it refers to its parents scope whenever called.

function Employee() {
    this.name = 'Anna',
    this.age = 25,
    this.sayName = function () {

        console.log(this.name);
        let Func = () => {
            console.log(this.name);
        }

        Func();
    }
}
const x = new Employee();
x.sayName();
Output:

Anna

Anna

Func() is defined within arrow. Inside the arrow this keyword refers to parents scope and returns this.name as Anna.

Argument bindings:

Arrow functions don’t have argument bindings.

let x = () => {
    console.log(arguments);
}
x(10, 20); // error
Output:

Reference error

To solve this use spread syntax.

let x = (...n) => {
    console.log(n);
}
x(10, 20); // [10, 20]
Output:

[10, 20]

Limitations:
  • Arrow functions does not have bindings to this, arguments or super and should be used as methods.
  • Calling arrow functions with new throws type error. They cannot be used as constructor.
  • They cannot use yield within their body and cannot be created as generator function.
  •  You should not use arrow functions to create methods inside objects.
Key differences with Regular function:
  • No prototype object for arrow functions
  • Duplicate-named parameters are not allowed.
  • Does not have argument object.
When to use them?

Arrow functions can be used when we need to bind this to the context and not to the function itself. It is a clear and concise way to write callbacks without exposing the scope that should be hidden.

In the coming article will try to ellaborate the difference with regular functions.

Higher Order Functions and decorators in Python

Higher Order Functions:

Higher Order Functions (HOFs) are functions that express complex concepts by combining simpler functions into a new function. It is a function that contains a function as parameter and returns another function as a result.

Properties of Higher Order Functions:

  1. We can store a function inside a variable.
  2. A function can act as instance of an object
  3. We can pass a function as an argument to another function
  4. We can store Python higher order functions in data structures such as list, hash tables etc.,

Functions as object:

               In Python, a function can be assigned to a variable. Here, a reference to the function is created.

Example:

Passing Function as an argument to another function:

Functions are like objects in Python, so they can be passed as an argument to another function.

Returning Function:

As functions are objects, we can also return a function from another function.

Decorators as Higher Order Function:

               We can use decorators as higher order function. Decorators in Python allow us to extend behavior of methods or functions without explicitly modifying it.

Decorators allow us to wrap another function to extend the behavior of wrapped function, without modifying it.

Syntax:

# Using a decorator  

@myDecorator  

def Python_Decorator():   

.

.

The above decorator syntax is equivalent to the below syntax for using decorator as higher order function in python.

def Python_Decorator():   

    .  

    .  

Python_Decorator = @myDecorator(Python_Decorator)  

Example:

In the next article we will see about map(), reduce() and filter() higher order functions.