Objects, this, call, bind and apply in javascript

Objects, this, call, bind and apply in javascript

Β·

8 min read

Hey Everyone πŸ‘‹πŸ‘‹,

I'm Akshay, in this article we will be discussing Objects in javascript, and the topics we are going to cover are:

  • Objects
  • This
  • Call, apply and bind
  • Polyfills for the above method,

Let's go πŸš€ πŸš€ πŸš€

Before I jump in and start explaining the above topics let's cover some basics so that we will be able to understand Objects a level deeper.

Objects in Javascript

Javascript is a multi-paradigm Scripting language that means it supports both Object-oriented programming with prototypal inheritance and functional programming. In my previous blog here, I talked in detail about functional programming in JS, in this, I will be covering Objects.

What is an Object

Objects is a collection of property stored as a key-value pair, the property can also be a function, in that case, it is called a method, or properties in the object is nothing but a variable that is attached to a value.

Different ways of creating an object.

1) Using object constructor

let obj = new Object();

In the above code, we are declaring a variable obj using let followed by a new keyword and Object this code will generate a new empty object, when we console log obj, it will show us { }

2) Using Object.create method

let obj = Object.create(null);

The code is similar to the 1st one except we are using Object. create and passing in a null value 🚫 Disclaimer: it is important to add an { } object or null inside Object. create or else it will throw an error saying Object prototype may only be an Object or null: undefined

3) Using object literal

let a = {}

In the above code, you are assigning an empty object to the variable a, it will also create an empty object, you can even directly assign value to the object while declaring.

4) Using function constructor

let Obj = function(name) {
  this.name = name
}
let c = new Obj("hello");

In javascript, a function constructor can be used to create a template for the object, one advantage of this is, you can create multiple instances of the object without having to create and assign properties every time, in the above code that variable c is the newly created instance of the function Obj, and we are passing the name as the argument, the output of the above code looks like this

Obj { name: 'hello' }

5) Using ES6 class syntax

class myObject  {
  constructor(name) {
    this.name = name;
  }
}
var e = new myObject("hello");

The above code is similar to the function constructor except we are using Class and Object

Classes are a template for creating objects. They encapsulate data with code to work on that data. Classes in JS are built on prototypes but also have some syntax and semantics that are not shared with ES5 class-like semantics. Constructor is a special keyword for initializing an object created with class, there can only be one constructor in the class, and here to we have created an instance of a class, and the output looks like

myObject { name: 'hello' }

you might have observed we have been using this keyword in some of the places, what exactly are they?

this in Javascript.

Every execution context provides this keyword, which points to an object to which the current code that’s being executed belongs.

The value of this in javascript is dynamic and depends on many factors such as :

  • function invocation
  • method invocation
  • constructor invocation
  • Arrow function

🚫 Disclaimer: in this article, we will be discussing this in reference to the javascript environment, not in the node environment since the node tends to behave differently for the this keyword.

let get started

1) Function invocation

The value of this inside a function is usually defined by the function’s call. So, this can have different values inside it for each execution of the function.

The function is invocated when an expression that evaluates a function object is followed by an open parenthesis like ( ), to execute the code that is present inside the function.

In non-strict mode, the this keyword will be equal to the window

function test() {
  console.log(this==window);
}
test()
//true

Even in the nested function, the value of this will be equal to the window

function test2() {
  console.log(this===window); //true
}

function test() {
  test2()
}
test()

2) method invocation

The property of an object which is a function is called a method

const test = {
  name: "akshay",
  place: function () {
    console.log(this.name);
  }
}
console.log(test.place());

above code is an example of a function with a method place storing the Function as a value, which can be accessed by calling test. place() now the value of the method is not global, the value of the method is the object inside which method has been used, so the above example will throw akshay as an output, but the moment we take the method outside the object and store it inside a variable then this will equal to global or window

const test = {
  name: "akshay",
  place: function () {
    console.log(this.name);
  }
}

let test2 = test.place
console.log(test2());

The output of the above code is undefined since the this value is not pointing to the object anymore

3) Constructorinvocation

Constructor invocation is performed when a new keyword is followed by an expression that evaluates to a function object, an open parenthesis (, a comma-separated list of arguments expressions and close parenthesis )

function Test() {
  this.name="akshay"
}

let newPerson = new Test()

In this case, the value of this will be equal to the newly created instance of the object.

4) Arrow function

ES6 introduced a new way of writing functions called arrow function, the value of this inside arrow functions are lexically determined, the arrow function does not have this keyword but in turn, they will be using its parents this.

let name = {
  place: "bglore",
  age: function () {
    let test = () => {
      console.log(this.place);
    }
    test()
  }
}

name.age()

here we are adding an arrow function inside method age, as we discussed above arrow function is borrowing the this from the outer parent function which is age, and printing the value bglore, if we had used normal function instead of arrow function, it would have thrown an undefined since the this of the newly created nested function will be pointing out to window instead of object name

Now, to set this keyword explicitly/independently instead of depending on how the function was invoked, we use the call, apply and bind method

1) Bind

The bind() method returns a new function that, when called, has this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

let obj1 = {
  name: "akshay",
place:"32"
}

function test() {
  console.log(this.name,this.place);
}

Here the value of this inside the function test is a window, but we want this of the function to be equal to the obj1, this can be achieved by using Bind, apply and call method, let's see how we can do that

let obj1 = {
  name: "akshay",
place:"32"
}

function test(time) {
  console.log(this.name,this.place,time);
}

let bindIt = test.bind(obj1, "12")
console.log(bindIt());

Here we are binding the function test with obj1, and it also accepts arguments, now the bind method will return us a new function which if invoke gives the output

akshay 32 12

You might be wondering how did that happen, how bind was able to connect this to function, to understand that, let's see how Bind works internally by creating our very own polyfill called myBind

Function.prototype.myBind = function (context, ...args) {
  let fun = this;
  context.bindedFun = fun;
  return function (...args2) {
    return  context.bindedFun(...args,...args2);
  };
};

In the above function, we are receiving context and arguments, the this is equal to the function on which we have called the polyfill, if you look closely we are adding the given function as a method inside the provided context and returning a function which if invoked, we are calling the method and now the this value of the method is equal to the context since it is present inside the context and similarly we are passing the given arguments by invoking the method, simple right?

2) Call

Call function also does the same job except that it's invoked as soon as a function is called with the .call method instead of returning a new function.

let obj1 = {
  name: "akshay",
  place: "bglore",
};

function callIt() {
  console.log(this.name, this.place);
}

console.log(callIt.call(obj1));

In the above code we can see that we are calling the function callIt and we are binding it on inside the ( ) operator, the output of the code is

akshay bglore

we can even pass multiple arguments while invoking the function.

Now that we have learned how .call works let's implement our own call function

Function.prototype.myCall = function (context, ...args) {
    let fun = this;
    context.myBindedFun = fun
    console.log(context);
   return context.myBindedFun(...args)
}

As you can see above we are doing the same thing as we did in our bind polyfill except for returning a new function, we are invoking the function.

3) Apply

Apply works just like call method except that it takes an array of arguments that we want to pass in instead of normal ones where we add argument separated by comma

Let's see an example

Function.prototype.myCall = function (context, ...args) {
    let fun = this;
    context.myBindedFun = fun
    console.log(context);
   return context.myBindedFun(...args)
}

let obj1 = {
  name: "akshay",
  place: "bglore",
};

function callIt(degree,frmaework) {
  console.log(this.name, this.place,degree,frmaework);
}

console.log(callIt.apply(obj1,["mech","react"]));

and the output of the code is

akshay bglore mech react

Polyfill for apply

Function.prototype.myApply = function (context, args) {
    let fun = this;
    context.myBindedFun = fun
   return context.myBindedFun(...args)
}

let obj1 = {
  name: "akshay",
  place: "bglore",
};

function callIt(degree,frmaework) {
  console.log(this.name, this.place,degree,frmaework);
}

console.log(callIt.myApply(obj1,["mech","react"]));

That's exactly the same as the call method except we are not spreading it at the first time when we receiving the argument

That's all folks for today's topic, hope you folks were able to understand the javascript function a level deeper and more clear.

Thank you. πŸ‘‹ πŸ‘‹

Β