In this article, the author, a front-end developer, gave an overview of the main ways of creating, modifying, and comparing JavaScript objects.Objects are one of the basic concepts in JavaScript. When I began to study them, they seemed to me quite simple: just a couple of keys and values, as described in theory.
Only after some time I began to understand that the topic was much more complicated than I thought. And then I began to study information from various sources. Some of them gave a good idea of the subject, but I could not see the whole picture at once.
')
In this post, I tried to cover all aspects of working with objects in JS, not going too deeply into specific details, but also without losing important details that will help you understand the subject and feel more confident during its further study.
So let's start with the basics.
An object
An object in JavaScript is simply a set of properties, each of which is a key-value pair. You can refer to the keys using the dot (
obj.a ) or bracket designation (
obj ['a'] ).
Remember that brackets should be used if the key is:
- is not a valid JavaScript identifier (there is a space in it, a dash, starts with a digit ...)
- is variable.
One of the properties that objects in JS get when they are created is called
Prototype , and this is a very important concept.
Prototype
Every object in JavaScript has an internal property called
Prototype . In most browsers, you can refer to it by the symbol
__proto__ .
Prototype is a way to ensure the inheritance of properties in JavaScript. So you can share the functionality without duplicating the code in memory. The method works by creating a connection between two objects.
Simply put, Prototype creates a pointer from one object to another.
Prototype chainEvery time JS searches for a property in an object and does not find it directly at the object itself, it checks the presence of the property in the prototype object. If there is no property in it, then JS will continue the search in the prototype of the associated object. This will continue until JS finds a suitable property or reaches the end of the chain.
Let's look at an example:
var cons = function () { this.a = 1; this.b = 2; } var obj = new cons(); </i> cons.prototype.b = 3; cons.prototype.c = 4;
cons is a constructor (just a function that can be called using the
new operator).
On the fifth line, we create a new object — a new copy of
cons . Immediately after creation,
obj also receives the property of the prototype.
And now we add properties (
'b', 'c' ) to the
cons object prototype.
Consider
obj :
obj.a // 1 - here everything is as
before ,
obj.a is still equal to 1.
obj.c -
obj has no
c property! However, as previously mentioned, JS will now search for it in the prototype
obj and return the value 4.
And now let's think about what the value of
obj.b is and what will it be when we remove
obj.b ?
Obj.b is equal to 2. We assigned the property
b , but we did it for the
cons prototype, so when we check
obj.b , we still get 2. However, immediately after removing
obj.b, JS will not be able to find
b at
bj , and therefore will continue the search in the prototype and return the value 3.
Next, I want to briefly talk about various ways to create an object and a little more about prototypes.
Object creation
Object literal: let obj = {a: 1};We created an object with the following prototype chain:
obj ---> Object.prototype ---> nullAs you can guess,
object.prototype is the prototype of the object, as well as the end of the prototype chain.
Object.create (): var newObj = Object.create (obj);NewObj will have the following prototype chain:
newObj ---> obj ---> Object.prototype ---> nullConstructor. As in the example above, the constructor is just a JS function, which allows us to use the
new operator to create new instances of it.
ES6 classes: class rectangle { constructor(height, width) { this.height = height; this.width = width; } getArea() { return this.height * this.width; } } let square = new rectangle(2, 2);
Square is an instance of the
rectangle constructor, and therefore we can call
square.getArea () // 4 ,
square.width , as well as all the functions inherited from
object.prototype .
Which way is better? If you plan to create multiple instances, you can use ES6 or Designer. If you plan to create an object once, it is better to specify a literal, since this is the easiest way.
And now, when we learned about
prototype and got acquainted with all the ways to create new objects, we can proceed to discuss one of the most confusing moments associated with objects.
Comparing and modifying objects
In JavaScript, objects are of reference type.When we create a
let object
obj = {a: 1}; , the variable
obj gets the address in the memory of the object, but not its value! It is extremely important to understand this difference, because otherwise errors can occur. When we create another object
let newObj = obj , we actually create a
pointer to a certain memory area
obj , and not a completely new object.
This means that by executing
newObj.a = 2 , we actually change
obj so that
obj.a becomes equal to 2!
This approach easily leads to the appearance of bugs, so many companies work with immutable objects. Instead of changing an already created object, you will have to create a new object again (a copy of the original) and make changes already in it. This is how important libraries like Redux work, and in general this is one of the main concepts of functional programming. You can read more
here .
EqualityIt also follows from the above that two objects can never be equal, even if they possess the same properties. This is due to the fact that JS actually compares the location in the memory of objects, and two objects are never in the same memory cell.
So, you most likely have already wondered how you can compare objects or how to perform various manipulations with objects, given the requirement for their immutability.
Consider several possibilities.
Object changeSuppose it is clear that in a good way we should not change objects, so we want to create a copy of the corresponding object and change its properties.
Object.assign () comes to the
rescue .
var obj = { a : 1, b : 2}; var newObj = Object.assign({}, obj,{a:2})
If we want to change the value of the
a property of the
obj object, we can use
object.assign to create a copy of
obj and modify it.
In the example, you can see that we first create an empty object, then copy the
obj values and make our changes, eventually getting a new and ready-to-use object.
Please note that this method will not work for deep copying. Speaking of deep copying, we mean that you need to copy an object with one or more properties.
const obj = {a : 1, b : { a : 1 } };
Object.assign () copies the properties of an object, so if the value of the property is a pointer to an object, only the pointer is copied.
Recursive operation is required for deep copying. Here you can write a function or simply use the
_.cloneDeep method from the
Lodash library.
Comparison of objectsThere is one cool way to work with objects - a string conversion. In the following example, we convert both objects into strings and compare them:
JSON.stringify(obj1) === JSON.stringify(obj2)
This approach is justified, because in the end we compare the strings, which are a pointer to a type-value. The bad news is that it does not always work, mainly because this or that order of properties of an object is not guaranteed.
Another good solution is to use the
Lodash _.isEqual method, which performs a deep comparison of objects.
And before you finish, let's go over some of the frequently asked questions on the subject of objects. This will help to dive deeper into the topic and apply the knowledge gained in practice.
Try to think about the solution yourself before reading the answer.
How to know the length of the object?
To get the answer, you must go through all the properties of the object one by one and count them. There are several ways to perform this iteration:
- for in . This method covers all the countable properties of an object and a chain of its prototypes. We met with the prototype (and, I hope, learned the material), so it should be clear that the use of for in will not always be correct for obtaining the properties of the object.
- Object.keys . This method returns an array with the keys of all its own (belonging to the specified object) counting properties. This approach is better, since we only work on the properties of the object, not referring to the properties of the prototype . However, there are situations when you set the enumerable attribute of a property to false, and object.keys eventually misses it, and you get an incorrect result. This happens rarely, but in such cases, getOwnPropertyNames will be very useful.
- getOwnPropertyNames returns an array containing all the object's own keys (both countable and uncountable).
Also worth mentioning are:
- Object.values enumerates its own countable properties and returns an array with the appropriate values .
- Object.entries enumerates its own countable properties and returns an array with keys and their values .
I think you noticed that most of the above methods return an array. This is an opportunity to take full advantage of JavaScript methods for working with arrays.
One of these methods is
array.length . As a result, we can just write
let objLength = Object.getOwnPropertyNames(obj).length;
How to check if an object is empty?
- JSON.stringify (myObj) === “{}” . Here, we again use the string conversion tool to easily check if the object is empty (comparing strings, not objects).
- ! Object.keys (myobj) .length // true . As I mentioned, converting object keys to an array can be very useful. Here we use the convenient length property inherited from Array.prototype , checking with it the length of the keys in the array. In JS 0 it turns into false, therefore adding ! we make it true. Any other numbers will turn false.
Finally
I hope, now you feel more confident in creating objects and working with them. Let's summarize:
- Remember that objects belong to the reference type, which means that it is recommended to work with them without changing the original objects.
- Make friends with the prototype property and the prototype chain.
- Get acquainted with the tools, assistants in working with objects. Remember that you can turn objects into strings, get an array with their keys, or simply iterate over their properties using a set of methods that we met.
Good luck learning JavaScript objects.
