Skip to main content

Command Palette

Search for a command to run...

Object Fundamentals and DeepDive

Updated
7 min read
Object Fundamentals and DeepDive
J
I am Jay Ahirrao, currently pursuing a BTech in Information Technology at JSPM's Rajarshi Shahu College of Engineering, Pune. I previously earned a Diploma in Computer Technology from Government Polytechnic Nashik, where I developed strong proficiency in programming languages such as Java , C , C++, Python, and SQL . Additionally, I have explored Full-Stack Web Development, focusing on the MERN stack and React.js. I’m passionate about Tech and continuously seek opportunities to learn and grow. Whether contributing to innovative projects, advancing personal development, or Solving Challenging Technical Problems, I am dedicated to Enhancing my skill set.

An object is a non-primitive data type.

While a string is just a value, an Object is a reference to a memory location containing key-value pairs.

# Creating the Entity with Features (Object Creation)

  1. Object Literal: const obj = {} (Fastest, most common).

  2. Constructor: new Object() (Our code: const o = new Object({})) , mostly same as Literal, but literal obj creation is Faster.

  3. Object.create(): Creates a new object using an existing object as a prototype.

# Accessing & Updating

  • Dot Notation: o2.name (Simple, clean).

  • Bracket Notation: o2["name"] (Powerful; allows using variables as keys).

const person = { 
    isHuman: false, 
    printIntroduction() { 
        console.log(`Am I human? ${this.isHuman} `)
        console.log(`Am I human? ${this["isHuman"]}`)
    } 
}   

const me = Object.create(person) )
  1. Factory Functions: Functions that return an object. Great for creating many similar objects without new.
function createPerson(name, age) {
  return {
    name: name,
    age: age,
    greet() {
      console.log(`Hello, my name is \({this.name} and I am \){this.age} years old.`);
    }
  };
}

// Creating objects using the factory function
const person1 = createPerson('Leo', 23);
const person2 = createPerson('Anup', 24);

person1.greet(); // Out: Hello, my name is Leo and I am 23 years old.
person2.greet(); // Out: Hello, my name is Anup and I am 24 years old.
  1. Constructor Functions: Uses this and new.
function Person(first, last) 
{
  this.firstName = first; // 'this' refers to the new instance
  this.lastName = last;

  this.sayName = function() {
    console.log(this.firstName + " " + this.lastName);
  };

}

// Creating new instances using the 'new' keyword
const jay= new Person("Jay", "Ahirrao");

jay.sayName(); // Output: Jay Ahirrao

What new Does Behind the Scenes:

  1. Creates a new empty object: {}.

  2. Binds this to that new object.

  3. Sets the new object's internal __proto__ property to the constructor's (function's)prototype.

  4. Executes the constructor function code.

  5. Returns the object automatically (if no explicit object is returned).

  6. Classes: ES6 "Syntactic Sugar" for Constructor Functions.

Accessing the Systems

  • Dot Notation (obj.prop): Used when we know the key name.

  • Bracket Notation (obj["prop"]): Mandatory if the key has spaces, starts with a number, or is stored in a variable (e.g., obj[keyName]).

2. Security Protocols: Mutability Control

JavaScript objects are "mutable" by default (we can change them).

Our code explored the three levels of "Locking" an object.

  1. Object.preventExtensions(obj): (Level 1) We can't add new properties. We can delete or change existing ones.

  2. Object.seal(obj): (Level 2) We can't add or delete properties. We can change existing values.

    const o3 = {
        name: "bijoy",
        age:47
    }
    console.log(o3);
    
    Object.seal(o3)
    
    o3.name = "joy";
    o3.gorapan = 100 // not error
    
    console.log(o3);
    
    • In our code: o3.name = "joy" worked because it was an update, but o3.gorapan failed because it was an addition.
  3. Object.freeze(obj): (Level 3) The "Ultimate Lock." No additions, no deletions, no updates.

    const o2 = {
        name: "Narayan",
        stealth:54
    }
    console.log(o2);
    
    Object.freeze(o2)
    
    o2.name = "Jay";
    o2.strength = 99; // not error
    
    console.log(o2);
    
    • In our code: o2.name = "Jay" failed silently (or throws an error in strict mode).

3. The Classified Files: Property Descriptors

Every property in an object has "meta-data" called Attributes. We accessed these via Object.defineProperty.

const sec = { name: "diamond" } 

Object.defineProperty(sec, "MRP", 
{ 
    value: 78_00_000, 
    writable: false, 
    enumerable: false, 
    configurable:false
}) 

console.log(sec.MRP); 

sec.MRP = 58_00_000 
console.log(sec.MRP); // value gets changed

for(const [k,v] of Object.entries(sec)){ 
    console.log(\({k} : \){v}); 
} 

console.log(Object.getOwnPropertyDescriptor(sec, "MRP")); console.log(Object.getOwnPropertyDescriptor(sec, "name"));
  • value: The actual data.

  • writable: If false, the value cannot be changed.

  • enumerable: If false, the property is invisible to loops (for...in) and Object.keys().

    • Note: Here, MRP was hidden because we set this to false.
  • configurable: If false, we cannot delete the property or change these attributes again.

4. Navigation Systems : Iteration (Looping)

How do we walk through a jet's inventory?

  • Object.keys(obj): Returns an array of keys.

  • Object.values(obj): Returns an array of values.

  • Object.entries(obj): Returns an array of [key, value] pairs. (Used in our for...of loop).

  • for...in loop: Iterates over all enumerable properties, including those in the prototype chain.

5. The "This" Radar : Execution Context

This is the most complex system. this is a pointer to the owner of the current code execution.

const go = {
    sname: "jay", 
    wins: 49, 
    loss: 0, 
    belts: ["global champion", "undisputed", "uncrowned"], 
    introduce() {
    console.log(\({this.sname} has \){this.wins} wins & ${this.loss} losses); 
    
        this.belts.forEach((element, idx) => { 
            console.log(belt no \({idx + 1} : \){element} ); 
        }); 
    } 
} 

go.introduce();
  1. Global Context: In the open air (global), this is the window (or global in Node).

  2. Function Context:

    • Simple Call: func() -> this is Global/Undefined.

    • Method Call: obj.method() -> this is obj.

  3. Arrow Functions: As we've seen in our Arrow Function Blog ... They do not have a this. They use Lexical Scoping , meaning they look at their parent's this at the moment they are defined.

    • In our go.introduce() code: The forEach arrow function successfully uses the this from introduce to see this.sname. If that was a regular function, this.sname would be undefined.

6. The Blueprint: Prototype vs. Class

When building a fleet of jets, we don't want to waste memory.

The Prototype Chain

Every object has a hidden link ([[Prototype]]) to another object. If we look for a property on d1 and it’s not there, JS looks at myCar.prototype.

  • Memory Efficiency: Methods added to the .prototype (like our getDetails) are stored once in memory.

  • Instance Methods: Methods defined inside the constructor (like our myCar2) are duplicated for every single instance created. Don't do this for large apps!

//TIP : A 'regular nested function & a normal arrow function' doesnt inherit "this" 
// but nested arrow function does


// constructor function
function myCar(name, age, hope) {
    this.name = name;
    this.age = age;
    this.hope = hope;
}

myCar.prototype.getDetails = function () {
    return `Oh "\({this.name}", u are hoping to get \){this.hope}, are you SANE ? No Doubt , your age is ${this.age} !`
}

const d1 = new myCar("Jay", 20, "BMW")
const d2 = new myCar("Jay", 20, "Range Rover")

console.log(d1.getDetails());

Classes

class is the modern way to write prototypes.

  • Constructor: Runs once when we use new.

  • Methods: Automatically added to the prototype.

  • Instance Properties: Properties like this.name are unique to each object.

class Cricketer  {
    constructor(name, role) {
        this.name = name
        this.role = role
        this.jerseyno = undefined
        this.undefined = null // beacomes this."undefined" as in prope name
    }

    introduce(){
        console.log(`\({this.name} is \){this.role} and \({this.jerseyno} with \){this.undefined}`);
        
    }
}

7. Memory Management: Factory vs. Constructor

  • Factory Functions: Clean, no this headaches, but every object carries its own methods (higher memory).

  • Constructor/Classes: More technical, uses this and prototype, but extremely memory-efficient for thousands of objects.

Common Consfusion about - key style , and new vs { } creation

const obj1 = new Object(
{ 
    name: String, 
    inter(){ console.log(`this is \({this.name} \){this["name"]}`); }
})

const obj2 = new Object(
{ 
    "name": "JAy", 
    inter(){ console.log(`this is \({this.name} \){this["name"]}`);} 
}) 


const obj3 = new Object(
{ 
    name: "JAy", 
    inter(){ console.log(`this is \({this.name} \){this["name"]}`);} 
}) 

const o2 = { name: "Narayan", stealth:54 }
  • obj1: The name property is set to the String constructor function itself, not a string value. Calling obj1.inter() would print: "this is function String() { [native code] } function String() { [native code] }" [2].

  • obj2 and obj3: These are functionally identical. In JavaScript, name and "name" as keys are treated the same [1]. Calling inter() on either will print: "this is JAy JAy".

  • o2: This is a standard object literal. It’s the most common and concise way to create an object compared to the new Object() syntax used above [1].

5 views