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. π π