JavaScript Objects

JavaScript Objects

There are two types of Datatypes in JavaScript, primitive and non-primitive. An object is non-primitive datatype.

Nearly all objects in JavaScript are instances of Object; a typical object inherits properties (including methods) from Object.prototype , The only entities that don't inherit from Object.prototype are those with null prototype, or descended from other null prototype objects.

An object is a collection of related data and functionality. These usually consist of several variables and functions (which are called properties and methods when they are inside objects).

Let's understand the object in parts

Nearly all objects in JavaScript are instances of Object;

part 1

const obj1 = {
  name: "Sudhanshu",
  lastName: "Modi",
  fullName: function () {
    return this.name + " " + this.lastName;
  },
};

Here, an object is defined and the name of that object is obj1.

There are some values and functions inside it, we name name: "Sudhanshu" as properties and fullName: function () { } as methods.

values stored inside objects as key-value pairs where name is the property key and "sudhanshu" is the property value.

There can be any type of value in the place of "sudhanshu" , it can be of any datatype such as an array, a number, or an object itself.

add data in an object

obj1["hii"] = "hello";
console.log(obj1);

// output
{
  name: 'Sudhanshu',
  lName: 'Modi',
  fullName: [Function: fullName],
  hii: 'hello'
}

access data of an object

console.log(obj1.name);

// output
Sudhanshu

we can access data with dot(.) notation, objectName.propertyName , you can also use methodName in place of propertyName when you want to access methods that all work the same.

console.log(obj1.fullName());

// output
Sudhanshu Modi

We can understand later how this works.

part 2

const obj2 = new Object(); //constructor
obj2.rBook = "redBook";
obj2.Value = "108 Book";
console.log(obj2);

// output
{ rBook: 'redBook', Value: '108 Book' }

This is the same as part 1, it is just constructor-based syntax.

part 3

Object.create()

What happens is usually we pass an object inside this something like

const obj3 = Object.create({})

but there is a very very rare chance that you use this syntax, this syntax is used when you want to copy an existing object or want to inherit the properties from an existing value.

const powers = {
  fly: true,
  cordinate: Math.random() + 2,
};

now we want to inherit, in obj3 all these powers should be added, It should be an object itself but it also should have all these powers as well.

This is my goal, I want obj3 to be a stand-alone object but I also want to adopt all the powers as well.

So what do you, do you simply go and do

const obj3 = Object.create(powers);

now we have adopted these powers, I just told you that the syntax Object.create() is majorly used to inherit the powers but what, strange I will see that if I go and do

console.log(obj3);

// output
{}

Now this is where things go crazy

Why do we see an empty object here, why is that this was supposed to work, but interestingly you will see that if I go and duplicate this, and I do

console.log(obj3.cordinate);

// output
2.043435696597596

If the object has no properties it should not work but to your surprise, this will work.

This brings us back to the start of the topic, Let's run the same code inside the browser this will help us understand better

Notice here, that the code is the same and this is pointing toward an empty object When we open this up notice here there is a prototype and when we open this again we have cordinate and fly . So what this is doing when we use Object.create() whatever the previous inherited properties are through it into your prototype like you have access to them but in general it will look much cleaner that there is nothing inside the object, you can access them but it will make it a little bit cleaner by not giving you a bulky object maybe there are 100 properties into that so it will just keep your object clean so your new object obj3 is very clean there is nothing inside it but somehow you want to access it, it will give you the access of it.

Now it makes a lot more sense, One more thing it's not like we always have to go to the browser to see what all properties are, we can go ahead and find it out by saying

console.log(Object.getPrototypeOf(obj3));

// output
{ fly: true, cordinate: 2.043435696597596 }

Now it gives all the prototypes, so it is there it is just hidden from us.

So one thing is clear so far everything is an object and we have to always worry about what is inside our object and what is inside that prototype also

I told you that everything here is a prototype, and even if you declare a variable name or something like that for example when we run code inside the browser and we try to access it there are many other prototypes as well.

I never declared hasOwnProperty property I never declared toString property I never declared valueOf but these were given to, so this is exactly the meaning of the line when it says Nearly all objects in JavaScript are instances of Object;

so somehow they are inheriting the property not just the power, If they are instances of an object that means they will inherit some of the property from their parent it is usually always in the property, it could be a toString property it could be toLocaleString property whatever that is they are inheriting some of the things.

part 4

const obj4 = Object.create({});

Hey, object I want to use your create method and I will this time pass you as an empty object, you don't inherit any power like that you just do work like that

so since I am not inheriting anything, obviously this is an empty object now, so now I want to add some property in my empty object which is obj4.

There is no problem with adding property in the obj4 as we do in part 1 and part 2 like this obj1["hii"] = "hello" or obj2.rBook = "redBook"

obj4.name = 'Sudhanshu';
obj4['lastName'] = 'Modi'
console.log(obj4);

// output
{ name: 'sudhanshu', lastName: 'Modi' }

But if you have used object.create(), the preferred method is that you go ahead and say

Object.defineProperty(obj4, "book", {
  icon: "red Book",
});
console.log(obj4);
console.log(Object.getPrototypeOf(obj4));

// output
{}
{}

when you use Object.defineProperty() It has no idea in what object you want to insert values so the first parameter is obj4, This is my targeted object where I want to insert some values and then it says What is the key, I say the key is going to be book and then what is the value, in this case, you can add any value any descriptive but I want to inject an object into this, for now, I add an icon property and that icon is going to be just red Book.

But when we do console.log(obj4); and console.log(Object.getPrototypeOf(obj4));It gives us an empty object.

You may think it is a problem, but it is not a problem it is working of JavaScript

The reason why this Object.defineProperty() is created so that you can add properties to the object not any properties but the properties that you can control more, the way I want to say control more is that if you wanted some property to be returned, you actually cannot do this 'icon' kind of stuff.

You have to use methods, especially getters and setters In case you have studied C++ or something like that, then what I have to do is use a special syntax, I have to say get: ()=> "red book" which is going to return a 'red book'

Object.defineProperty(obj4, "book", {
  get: () => "red book",
});
console.log(obj4);
console.log(Object.getPrototypeOf(obj4));

// output
{}
{}

Here we run it again, This is still empty so to get this 'red book' back, we have to say console.log(obj4.book);

Object.defineProperty(obj4, "book", {
  get: () => "red book",
});
console.log(obj4.book);

// output
red book

So it has access to this getter now

Remember when we run console.log(obj4); It's an empty object, but you need to know the property of it and then you can grab it like console.log(obj4.book);.

this is where you have to use getters and that is the way how it is defined.

Important: Now I will introduce you to one more topic which is super super important if you will be working in the backend development

Now what I want is, I want a simple loop

const obj4 = Object.create({});
Object.defineProperty(obj4, "book", {
  get: () => "red book",
});
for (k in obj4) {
  console.log("value is: ", k)
}

// output

It gives me nothing, Is my 'obj4' not enumerable, Is it not loopable

We have the 'book', I should be able to get this

Why should I say obj4.book

why is it not working? Remember we wrote a simple object this is exactly the same No no no

This is where an interesting property comes up, this is such a powerful thing Object.defineProperty() Here you have to make sure something is enumerable or not

So you have to mention a property known as enumerable and you have to turn this flag on enumerable: true Now somebody can actually iterate through it, now if we run this

const obj4 = Object.create({});
Object.defineProperty(obj4, "book", {
  get: () => "red book",
  enumerable: true,
});

for (k in obj4) {
  console.log("value is: ", k)
}

// output
value is:  book

Now you get value as a book

just to understand what this enumerable: true does, that not all objects can be looped through, and if there is a problem in looping the objects it's not just your code is bad sometimes there is a restriction in the object that you cannot loop through it.

It happens especially when you working with Mongoose models and specials the database that comes up from the firebase or something like that

So you have a lot of control in JavaScript, a lot of access to in-depth details of it but since nobody goes in this much depth about how it works and what goes on and how it works, usually people just blame JavaScript as quirky language or is behaving badly, no it does not behave badly it's that we have not actually go thrown this much of in-depth.

It's not a good thing that you have an enumerable default, If you want something to be enumerable you have to explicitly mention it.

This is a common problem that you are going to see in Python language, By default things are enumerable and it is really bad.

languages see a lot of deficiency on a lot of projects when working with it, Python faces some slowness because of this enumerable.

part 5

const obj5 = {
  comics: "marvel",
  pen: "",
  printComicNormalFun: function () {

  },
  printComicArrowFun: () => {

  },
}

It is also possible in Objects that you can define functions but the part when you come into the Objects we call them methods they are the same things

There are two ways, we can define methods one like printComicNormalFun: function () { } and another is like printComicArrowFun: () => { } , These two are drastically different, mechanisms-wise What do you want to achieve with these methods, That is where you have to make a decision that I will use printComicNormalFun: function () { } syntax or I will use printComicArrowFun: () => { } syntax

There is nothing wrong or right there is the intention of what I want to achieve, so let's understand it

Normal Function Syntax

let pen = "abovePen";
const obj5 = {
  comics: "marvel",
  pen: "",
  printComicNormalFun: function () {
    pen += "funPen";
  },
}

My goal here is to add something in the pen so I want to update the variable.

But I cannot do it, the reason why I cannot do it is because I am too nested in-depth.

printComicNormalFun: function () { pen += "funPen"; }, the function doesn't know that there are some variables defined above me and what if the variables are defined way above in the file and maybe somebody used just above the obj5 a pen, How do I know that I want to target the pen which is inside obj5, why should I care about what thousand people are writing in my code there might be a hundred developers who are working on that and they might also be using a variable pen so how should be I absolutely hundred percent sure that I want to use pen inside obj5.

This is where the keyword comes up this , this simply means I want to refer to the properties that are inside obj5, this simply refers to the properties that are inside your Object.

If you want to target the pen which is inside obj5 not at the pen which is not inside obj5 then simply say this that's it

let pen = "abovePen";
const obj5 = {
  comics: "marvel",
  pen: "",
  printComicNormalFun: function () {
    this.pen = "funPen";
  },
}

obj5.printComicNormalFun();
console.log(obj5.pen);

// output
funPen

Arrow Function Syntax

let pen = "abovePen";
const obj5 = {
  comics: "marvel",
  pen: "",
  printComicArrowFun: () => {
    this.pen = "funPen";
  },
}

obj5.printComicArrowFun();
console.log(obj5.pen);

// output

Now the problem is if we go ahead and use another syntax that I don't want to use Normal function I want to use the Arrow function then it gives me nothing because the design of the Arrow function is the way it was designed in the JavaScript is you cannot use this In the Arrow function, you can but it won't work, or at least how we wanted it to work. So this is the reason why somewhere we use a normal function and somewhere we use an arrow function.

The arrow function doesn't have the context of this It was never designed to have the context

It is a common problem that a lot of people understand that this means the window object No this doesn't refer to the window object, if we run this in the browser then it refers to the window object, but this refers to the parent object.

const obj5 = {
  comics: "marvel",
  pen: "",
  printComicNormalFun: function () {
    console.log(this);
  },
  printComicArrowFun: () => {
    console.log(this);
  },
}
obj5.printComicNormalFun(); // it gives whole object
obj5.printComicArrowFun(); // it give nothing

// output
// obj5.printComicNormalFun();
{
  comics: 'marvel',
  pen: '',
  printComicNormalFun: [Function: printComicNormalFun],
  printComicArrowFun: [Function: printComicArrowFun]
}
// obj5.printComicArrowFun();
{}

see when we this With both methods normal function returns the whole object not only comics and pen but to these methods as well whereas the arrow function returns nothing.