Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

JavaScript Objects in Depth, Part 1: The Fundamentals

DZone 's Guide to

JavaScript Objects in Depth, Part 1: The Fundamentals

If you're new to JavaScript or need a refresher, this is a great tutorial for acquainting yourself with how JavaScript handles objects.

· Web Dev Zone ·
Free Resource

Introduction

JavaScript has two main data types: primitives and objects. The interesting thing here is that other than the primitive type everything else is an object, including functions. Therefore, if we are really interested in learning JavaScript, then understanding objects should be on the top in the list.

An object can be created with figure brackets ( {...}) with an optional list of properties where a property is a key:value pair, where the key is a string and the value can be anything. By anything, we mean it can be a primitive or an object or even a function.

// Object in JavaScript

let employee = {
    name : "Employee 1",
    experience: 3,
    skills: ['Java', 'JavaScript', 'Data Structure & Algorithm'],
    address: {
        landmark: 'xyz',
        city: 'Hyderabad',
        pin: 500032
    },
    getExceptedHike : function(){
        // do some logic
        return "Contact to Manager";
    }
};

In the employee object, we can observe and conclude that the properties of an object are in the "key:value" form, separated with a comma (,) and the value can be anything.

Furthermore, we can create an empty object using one of two syntaxes:

// Creating an Object
let ob1 = new Object();   // "constuctor object syntax"
let ob2 = {};             //"literal object syntax"

// Go to console and verify it's type

typeof ob1;  // return: "object"
typeof 0b2;  // return: "object"

In the above code, we can verify the type of ob1 and ob2 using the typeof keyword, which returns the variable's type(s). The whole point here is that we can create an empty object using the above two syntaxes.

Thought: Are these two empty objects the same?

Comparison Operators in JavaScript

Before we compare these two objects, first we must understand how comparison operators work. Unlike other programming languages, JavaScript has both strict and type-converting comparisons.

1. Equality ('=='): The equality operator converts the operands if they are not of the same type, then applies a strict comparison. If both operands are objects, then JavaScript compares the internal references which are equal when operands refer to the same object in memory.

2. Strict Equality ('==='): This is also known as an identity operator. It returns true if the operands are strictly equal with no type conversion.

// Equality operator
console.log(1.00 == 1);         // true
console.log("1" == 1);// true
console.log(1 == 1);// true
console.log("a" == 1);          // false

// Strict Equality operator
console.log(1.00 === 1);       // true
console.log("1" === 1);       // false
console.log(1 === 1);          // true
console.log("A" === 1);        // false

Line 8 might be confusing for those who are coming from a different programming language such as Java, C++, etc. You might think the typeof (1.00)is float/double, so how does the strict equality operator return true? The fact is that JavaScript has only number types, therefore 1 and 1.00 are both of type "number."

Now let's compare the two empty object and check the results.

let ob1 = new Object();
let ob2 = {};

if (ob1 === ob2) {
  console.log("Object are strictly equal");
} else if (ob1 == ob2) {
  console.log("Object are equal");
} else {
  console.log("Objects are not equal");
}

console:
Objects are not equal

Conclusion: Though both are the empty object, operands refer to a different object in memory. Hence they are not equal. TL;DR: No two empty objects are equal.

Accessing Object Properties in JavaScript

A property has a key (also known as a "name" or "identifier") before the colon (:) and the value to the right of it. We can access or set the property value using dot notation or Square Brackets. Note: We can use multiword property names (for example, "year of birth"), but then they must be quoted and to access this property it must use square brackets ([ ]) notation. Check the below example for more clarification:

let emp = {
  name: "Nitesh Nandan",
  email: "abc@mail.com",
  "year of Birth": 1996
};

// Aceessing the property
console.log(emp.name);  // Nitesh Nandan
console.log(emp."year of birth"); // Error: Uncaught SyntaxError: Unexpected string
console.log(emp.year of birth);   // Error: Uncaught SyntaxError: Unexpected string

console.log(emp["year of birth"]); // 1996

// Setting the property value

emp.name = "John Martin";          
emp["year of birth"] = 1980;
emp.city = "New York";   // Adding a new property city
console.log(emp.name);   // John Martin
console.log(emp.city);   // New York
console.log(emp.id);   // undefined

So this is how we access/set the property of an Object. In line 21, I have tried to access the property ("id") which is not a part of the object. If we try to access the property which is not present in the object it returns its value as undefined.

Now the question is, can we conclude if the value of some property is undefined? And, if so, then can we determine if the property itself is not defined? Let's check this example before we conclude:

let obj = {
    test: undefined
}

console.log(obj.test); // it's undefined, so - no such property??

Though line 5 returns undefined, technically speaking the property does exist. So the question remains the same: how can we check whether the property exists or not?

These are the ways to know whether the property exists or not:

console.log(obj.hasOwnProperty("test")); // true;
console.log("test" in obj);              // true;

console.log(obj.hasOwnProperty("name")); // false;
console.log("name" in obj);              // false;

So we can usethe in operator or the hasOwnProperty method to check for the existence of the property.

A situation like this very rarely happens because undefined values are usually not assigned. We mostly use null for "unknown" or "empty" values.

You might be wondering from where this hasOwnPropertycame from. If you are familiar with the Java language then you might know that each Java class implicitly inherits a Java object class. Similarly, each object in JavaScript inherits (prototype) an object and that has some common methods; hasOwnPropertyis defined there.

Image title

You can observe every object has a __proto__ which has an object as its value and if we expand that object we can see the methods. The detailed explanation is out of the scope of this article.

We can use a for loop and the in operator to walk over all the keys of an object. The syntax is:

let emp = {
  name: "abc",
  email: "abc@mail.com",
  "year of Birth": 1996
};

for (key in emp) {
  console.log(key + ": " + emp[key]);
}

Console(output):
  name: abc
  email: abc@mail.com
  year of Birth: 1996

Getters and Setters (JavaScript Accessors)

In JavaScript objects, there are two kinds of properties:

  1. Data properties: All the properties that we have been using up to now are data properties.
  2. Accessor properties: These are functions that work on getting and setting a value but look like regular properties.

Let's look at an example for more clarification:

let user = {
  _userName: "user123",
  _age: 18,

  get userName() {
    console.log("userName getter method is invoked");
    return this._userName;
  },
  set userName(name) {
    console.log("userName setter method is invoked");
    this._userName = name;
  },
  get age() {
    console.log("age getter method is invoked");
    return this._age;
  },
  set age(age) {
    console.log("age setter method is invoked");
    this._age = age;
  }
};

console.log(user.userName);
// userName getter method is invoked
// user123

console.log(user.age);
// age getter method is invoked
// 18

user.userName = "abcUser";
// userName setter method is invoked

user.age = 22;
//age setter method is invoked


console.log(user.userName);
// userName getter method is invoked
// abcUser

console.log(user.age);
// age getter method is invoked
// 18

So what we find here is that the getter/setter method is implicitly invoked whenever we are accessing or setting its value. In JavaScript, there is no concept of private attributes, therefore, in the community, we followed a convention that the attribute name which starts with "_" is a private attribute and one should not access it directly.

Do Yourself: Take the above code and remove the first character from attribute name, i.e "_", from all the attributes and execute. You will find something interesting; let me know in the comments.

We can add validation in the property with the help of accessor properties.

set userName(name) {
    if (name.length < 5) {
      console.log("Error: userName can't be less than five character");
      return;
    }
    this._userName = name;
 }

user.userName = "abc";
// Error: userName can't be less than five character

Object Cloning

Unlike the primitive data type, we can't copy an object. Copying an object creates one more reference to the same object. Let's check the example.

let ob1 = {
    name : "abc"
}
let ob2 = ob1;
console.log(ob2===ob1 && "Ob1 and Ob2 point to same object in memory.");
// Ob1 and Ob2 point to same object in memory.

So, by strictly comparing both objects, we have verified that both the references point to the same object in memory. In JavaScript, there is no built-in method for making a duplicate (exact clone) object. But if we really want that, then we need to create a new object and replicate the structure of the existing object by iterating over its properties and copying them on the primitive level one by one. The good thing is that we've already gone over how to iterate over object properties. You guessed it! We will be using the in operator.

let user = {
    name: "user1",
    age: "21"
}

let clone = {} // the new empty Object

// let's copy all user properties into it
for(let key in user){
    clone[key] = user[key];
}

console.log(user.name);  // user1
console.log(clone.name); // user1

console.log(user.age);   // 21
console.log(clone.age);  // 21

console.log(user!==clone && "Object Reference: user, clone points different object in memory." );
// Object Reference: user, clone points different object in memory.

We can also use the Object.assign method for the same purpose. It takes two arguments, dest and src1, src2, . . . , srcN (can be as many as needed) are objects, and returns an object.

Object.assign(dest, src1, src2, . . ., srcN).

It copies the properties of all object src1, . . ., srcN into dest.

let user = {
    name: "user1",
    age: "21"
}

let clone = Object.assign({}, user);

console.log(user.name);  // user1
console.log(clone.name); // user1

console.log(user.age);   // 21
console.log(clone.age);  // 21

console.log(user!==clone && "Object Reference: user, clone points different object in memory.");
// Object Reference: user, clone points different object in memory.

There are more ways to clone objects, which I will discuss in the next part of this tutorial.

This article covers the basic properties of JavaScript objects. In Part 2, I will go deeper into this concept. Let me know in the comment if you have any questions.

Topics:
web dev ,javascript tutorial ,javascript tutorial for beginners ,javascript objects

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}