A thing or two about Objects in JavaScript.

Objects are fundamental blocks in JavaScript. Understanding how objects work will definitely make your life a lot easier working with JavaScript.

what are objects? and why do we need them?

As a very simple definition, objects are nothing but collection of different types of data. When it comes to object oriented programming, its based on 4 core concepts.

  • Encapsulation.
  • Abstraction.
  • Inheritance.
  • Polymorphism.

For now, we will only look into how JavaScript deals with encapsulation parts and get back to the rest when we explain other concepts.

Encapsulation is a process of bundling different properties into one single reference variable. Objects are mainly used in places where we need to target multiple properties and methods(functions) under one roof. lets look into an example.

say we need to store a specific set of properties of all students in a class. Properties being name, age, marks in 3 subjects and a function which calculates the sum of the 3 subject marks obtained.

if this has to be done in a non object way(Procedural way), we should go about creating name variables for all the students, likewise do the same for their age property and marks property and have a function which takes in the all the subject marks as parameters and gives you a total.

let name1 = "Arun";
let name2 = "vaibhav";
let age1 = 23;
let age2 = 23;
....
function sumTotal(mark1,mark2,mark3) {
let sumMarks = mark1 + mark2 + mark3;
return sumMarks;
}
let totaMarks1 = sumTotal(23, 35, 35);
.... and so on for the rest.

Now lets look at object oriented approach.

function Student(name, age, mark1, mark2, mark3) {
this.name = name;
this.age = age;
this.mark1 = mark1;
this.mark2 = mark2;
this.mark3 = mark3;
this.sumTotal = function() {
let sumMarks = this.mark1 + this.mark2 + this.mark3;
return sumMarks;
}
}
student1 = new Student('Arun', '23', 35, 55, 63);
student1.totalMarks = student1.sumTotal();
student2 = new Student('vaibhav', '23', 55, 65, 73);
student2.totalMarks = student1.sumTotal();
// each students properties can be accessed by their properties name // and instance created. for eg, student1’s properties can be //accessed by,
console.log(`student name: ${student1.name}, student age: ${student1.age}`}

In the above example we can keep creating more student objects by calling the student constructor function, with the required parameters.

Even though this was a very simple example to understand objects in JavaScript, we are likely to encounter more such similar problems in our every day work. structuring our code become a lot simpler when you we take the object way over the procedural way.

Now we that we have known why we need objects, let see the different ways we could create one.

How to create an object?

We created the above object using an object constructor function. There are other ways of creating objects.

Different ways of creating an object.

  • object literal way
  • factory functions.
  • object constructor functions.
  1. Object literal way.
var a = {
color: "red",
name: "apple",
type: "fruit"
}
//notice the trailing comma after every line, this is optional for the last element(type: "fruit")

2. factory function.

function fruit(name) {
return {
color: "red",
name: name,
type: "fruit"
}
var apple = fruit("apple");

3. Constructor functions.

//By convention constructor function are always Capitalised.(first letter capital)
function Fruit(name) {
this.name = name,
this.color = "red",
this.type = "fruit",
}
var apple = new Fruit("apple");

when to use which method is entirely based on each ones use cases and preferences. But there are certain key distinct points that you can consider before choosing one option.

//object literal way.
var student1 = {
name: "Arjun",
age: 23,
marks = 53,
}
  • with the object literal notion you can always have only one object. Say in the example mentioned above to create an another student object, you need to copy the entire section again with different property values.
  • the Factory function and Constructor function lets you do the same thing, till we bring in the concept of prototypal inheritance. Protypal inheritance makes Constructor function the more efficient and preferred choice especially when we have many methods inside the object and its being used to instantiate multiple objects. Protypal inheriatance is a topic which requires a blog for itself, for now you can think protypal inheritance is concept by which constructor methods do not have to go about creating common functions every time a new object is instantiated. This makes the Constructor way of creating object more memory efficient when compared over the Factory functions.

Weighing down these points its totally upto the user to make a calculated decision on which method he wishes to settle for.

Ways of accessing/modifying Objects properties.

An object once created can be accessed, modified, new properties can be added, deleted with ease.

we can either do this using dot(.) notation or by square brackets[].

lets look into an example.

function Student() {
this.name = "Rahul";
this.section = "A";
this.age = 23;
}
var student1 = new Student();
var student2 = new Student();

in the code section above student1 variable will have access to all the properties of Student object and can access it either by,

//Dot notation
console.log(student1.name); // Rahul
console.log(student1.section); // A
//bracket notation
console.log(student1['name']); //Rahul
console.log(student1['section']); //A
//note : the key is wrapped within quotes if its the actual key, if //its a variable holding the key string, then you need not wrap them //within quotes. 
eg:
//let nameKey = "name";
//student1[nameKey] will produce the same result.

these two ways behave the same way in most of the cases where the key is a single word. In the above example when we say student1.section, the section is the key and the output(Rahul) is the value. suppose say there is a key by the name no of rooms in this case the dot notation would and we would be left with only square brackets to access the value of that particular key.

let house = {
"no of rooms": 3,
color: "red",
type: "individual"
}
//note while creating keys with spaces its mandatory to wrap them //within quotes, for single words its optional and they behave the //same way whether you wrap them or not.

In above example the house object is created with keys no of rooms, color and type. We would be able to access the color property and type by using either dot(.) notation or square brackets, but if we need to access the no of rooms then we will have to use only the square brackets with key wrapped within quotes.

console.log(student1['no of rooms']); //3

To conclude we can say, whatever expression is put inside the square brackets will be evaluated to have a string(key) present in the object, whereas in dot notation it blindly checks if the key after the dot is present in the object.

Similarly modifying/deleting object properties becomes straightforward just like accessing, using either dot notation/ square brackets.

let student = {
name: "Viggi",
}
student['name'] = "prashanth";
console.log(student.name) // prashanth {the value of name got //overwritten with prashant}
student['age'] = 23; // A new property called age got added to the //student object
student.age = 35; // age property of student object(earlier 23) got //overwritten by the (35)
delete student.age //age property of student gets deleted.
console.log(student.age) //undefined (since age got deleted with the //previous statement.

note: would suggest trying out all the operations with different edge cases and try understanding how object gets modified or behave in a particular way.

When Objects behave differently compared to primitive datatypes?

In javascript there are 5 primitive datatypes,

  • Integers
  • Strings
  • Boolean
  • Null
  • undefined.

these tend to behave differently when compared over objects. We shall specifically try focusing on pass by reference and pass by value with objects and primitive datatypes as one such distinction.

This topic can be better understood with an example.

Eg:1
let primitiveData = 10;
function dataModifier(data) {
data = 20;
}
datamodifier(primitiveData);
console.log(primitiveData); //10
Eg:2
let valueOne = 10;
let valueTwo = valueOne;
valueOne = 20;
console.log(valueOne); //20
console.log(valueTwo); //10

All primitive datatypes when passed as an argument or when copied to another variable is passed by value, which means each variable will hold just the value and any modifications done to one variable will not affect other variables which holds the same value.

Eg:1
let newObj = {
name: "Arun",
age: 23
}
function objectModifier(modifiedObj) {
modifiedObj.name = "Prashanth";
}
objectModifier(newObj);
console.log(newObj); // {name: 'Prashanth', age: 23}
Eg:2
let firstCar = {
company: 'Chevy'
}
let secondCar = firstCar;
secondCar.company = "Maruti";
console.log(firstCar.company); //Maruti
console.log(secondCar.company); //Maruti

The object newObj gets modified even though it was just passed to a function, and the modification was done on the modifiedObj variable name. The reason behind this behaviour is that all objects when passed as an argument to a function or copied to a variable, is passed by reference. which means all variables will be pointing to the same object reference and any modifications done to the object using these reference variable will reflect to all the variables pointing to this object.


Conclusion.

These are some shallow concepts on how Objects work in JavaScript. A much more in-depth journey towards Objects would be seen in upcoming posts. Happy coding!! Comments and feedback are most welcome.