You are on page 1of 36

Lecture # 3

Objects: A complete guide

Presented by:
Ahsan Ali Mansoor
3+ Years of experience / Team Lead (React JS)
Sr. Full Stack Developer at eBridge.tech
Objects
• Objects are used to store keyed collections of various data and more complex entities

• We can imagine an object as a cabinet with signed files. Every piece of data is stored in its file by
the key. It’s easy to find a file by add/remove a file its name(Key).

• An empty object (“empty cabinet”) can be created using one of two syntaxes:

let user = new Object(); // "object constructor" syntax


let user = {}; // "object literal" syntax

Note: Comparing two JavaScript objects will always


return false even with == operator.
Object - Literals and properties
• We can immediately put some properties into {...} as “key: value” pairs:
let user = { // an object
name: "John", // by key "name" store value "John"
age: 30 , // by key "age" store value 30
isMarried: false,
salary: null
};

• Delete a Property with delete operator (return true either property exist or not).
Syntax: delete person.age; // or delete person["age"];
• Access Property with Dot notation.
• Access Property with square brackets.
• Add a Property of any type.
• Keys can have space but accessible only with square brackets.
Objects – Computed properties
• We can use square brackets in an object literal. That’s called computed properties.
let userColor = 'fvtcolor';
user[userColor] = 'blue’
console.log(user)
The meaning of a computed property is simple: [userColor] means that the property name should be
taken from the variable userColor.

• We can use more complex expressions inside square brackets:


let day = ‘Monday’
user['weightOf'+ day] = 49
console.log(user)
Objects – Computed properties
• Reserved words are allowed as property names
A variable cannot have a name equal to one of language-reserved words like “for”, “let”, “return”
etc.
Basically, any name is allowed, but there’s a special one: "__proto__" that gets special treatment for
historical reasons.

let obj = { for: 1, let: 2, return: 3 };


Console.log( obj.for + obj.let + obj.return ); // 6
Objects – Property existence check
• With identical operator
Syntax: user.noSuchProperty === undefined //true means property doesn’t exist
There will be no error if the property doesn’t exist! Accessing a non-existing property just returns
undefined

• With “hasOwnProperty”
Syntax: user.hasOwnProperty("car") //true means property exist
There will be no error if the property doesn’t exist! Accessing a non-existing property just returns
undefined

• There is also exists a special operator "in" to check for the existence of a property.
Syntax: "key" in object
console.log('name' in user) //true means property exist
Property name usually a quoted string. If we omit quotes, that would mean a variable containing the
actual name will be tested.
Objects – Property existence check

“=== undefined” vs “in” operator vs “hasOwnProperty”

Usually, the strict comparison "=== undefined" check the property existence just fine. But there’s a
special case when it fails, but "in” and “hasOwnProperty” works correctly.

It’s when an object property exists, but stores undefined:


console.log(user.bloodTest === undefined) //returns true which is correct

user.bloodTest === undefined //add a property to user object

console.log(user.bloodTest === undefined) //Again returns true which means the property doesn’t
exist
console.log('bloodTest' in user) //true
console.log(user.hasOwnProperty('bloodTest’)) //true
Objects – “for…in” loop
To walk over all keys of an object, there exists a special form of the loop: for..in.

The syntax:
for (key in object) {
// executes the body for each key among object properties
}

let’s output all properties of user:


let user = { name: "John", age: 30, isMarried: false};
for (let key in user) {
console.log( key ); // Print Keys name, age, isMarried
console.log( user[key] ); //Print Value John, 30, false
}
Objects – “for…in” loop
Output order for non-integer keys will be same as creation

let user = { name: "John", age: 30, isMarried: false};


for (let key in user) {
console.log( key ); // Output will be name, age, isMarried
}
Objects – “for…in” loop
Output order for integer keys will be in sorting order.
Integer means: keys that can be converted into integers without a change

let codes = {
"49": "Germany",
"41": "Switzerland",
"44": "Great Britain",
"1": "USA"
};

for (let code in codes) {


console.log(code); // 1, 41, 44, 49
}
Objects – Comparison by reference
The equality == and strict equality === operators for objects work exactly the same.

Two objects are equal only if they are the same object. Means two variables pointing to same
object.
let a = {};
let b = a; // copy the reference

console.log( a == b ); // true, both variables reference the same object


console.log( a === b ); // true

And here two independent objects are not equal, even though both are empty:
let a = {};
let b = {}; // two independent objects
console.log( a == b ); // false
What is Deep Copy & Shallow Copy?
Deep Copy – by value:
Primitive values: strings, numbers, booleans – are assigned/copied “as a whole value” which is called
deep.

Shallow Copy – by reference:


Non primitive values i.e objects are not copied as whole value but as reference by default.
Example – Copying by Value (Deep Copy)
Let’s make a copy of Primitive value (“string”)
let message = "Hello!";
let phrase = message;

As a result we have two independent variables, each one is storing the string "Hello!".
Objects – Copying by reference (Shallow Copy)
By default, objects are copied by referenced (Shallow copied).
Means: A variable stores not the object itself, but its “address in memory”, in other words “a
reference” to it.

Here’s the picture for the object:


let user = {name: "John"}
Here, the object is stored somewhere in memory. And the variable user has a “reference” to it.

let admin = user; // copy the reference


Now we have two variables,
each one with the reference to the same object
Objects – Copying by reference

We can use any variable to access the cabinet and modify its contents:

let user = { name: 'John' };


let admin = user;

admin.name = 'Pete'; // changed by the "admin" reference


Console.log(user.name); // 'Pete', changes are seen from the "user" reference
Objects – Cloning (Deep Copy)
So, copying an object variable creates one more reference to the same object.

But what if we need to duplicate an object? Create an independent copy, a


clone?

There’s no built-in method for that in JavaScript. Actually, that’s rarely needed.
Objects – Deep Copy for primitive values
There are three methods of doing such thing but only for primitive values.
Objects inside objects still copied by reference but we will see later on how
to overcome this.

Method 1: for…in loop


let user = { name: "John", age: 30, kid: {class:"9th"}};
let clone = {}; // the new empty object
// let's copy all user properties into it
for (let key in user) { clone[key] = user[key];}
Objects – Deep Copy for primitive values
Method 2: Object.assign()
We can also use Object.assign to replace the loop for simple (primitive keys)
cloning:

let user = {name: "John", age: 30};


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

It copies all properties of user into the empty object and returns it. Actually,
the same as the loop, but shorter.
Objects – Deep Copy for primitive values
Object.assign & for in loop only for primitive keys.
Now it’s not enough to copy clone.sizes = user.sizes, because the user.sizes is
an object, it will be copied by reference. So clone and user will share the
same sizes:

let user = {
name: "John",
sizes: { height: 182, width: 50 }
};

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


console.log( user.sizes === clone.sizes ); // true, same object
Objects – Deep Copy for primitive values
Method 3: Spread Operator (we will learn in details in es6 lecture)
let objOne = {name: "sabir", class: 18}
let objTwo = {...objOne}
Object – Full Deep Copy Best way
There is a best way to create fully deep copy
Syntax: JSON.parse(JSON.stringify(object))

Let’s break into small parts


JSON.stringify(object) will convert the object’s keys and values into string
JSON.parse(object) will convert text into JavaScript Object
Object - Full Deep Copy Best way
Let’s take an example:
let user = { name: "John", age: 30, size: {width: 50, height: 300}};
let newAdmin = JSON.parse(JSON.stringify(user))

newAdmin.size.width === user.size.width //returns false this time

Off the note: When receiving data from a web server, the data is always
a string. Parse the data with JSON.parse(), and the data becomes a
JavaScript object.
Objects – Cloning (Summary)
With for…in loop
for (let key in user) { clone[key] = user[key];}

With ECMAScript 5: Object.create method


var foo = { a : 1 }; var bar = Object.create(foo);

With ECMAScript 6: Object.assign method


If you want shallow copy, use Object.assign({}, foo)

Spread Operator
let objOne = {name: "sabir", class: 18}
let objTwo = {...objOne}

With JSON.parse method (best way)


For "deep" copy, use JSON.parse(JSON.stringify(foo))
Objects – Merging with Object.assign
Merging two object into new one using Object.assign:
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };

Object.assign(ReciverObject, senderobject1, senderobject2);

Copy all properties from permissions1 and permissions2 into user


Object.assign(user, permissions1, permissions2);

If the receiving object (user) already has the same named property, it will be
overwritten.
Objects – Const object
Const only fixes the value of object itself. All object properties can be changed.
const user = {name: "John"}
user.age = 25; // (*)
console.log(user.age); // 25

The const would give an error if we try to set user to something else, for instance:
// Error (can't reassign user)
user = {
name: "Pete"
};
Objects – Property flags and descriptors
Problem: What if we want to fix object properties so they can not be changed?

Property flags
Object properties, besides a value, have three special attributes (so-called “flags”):

1. writable – if true, the value can be changed, otherwise it’s read-only.


2. enumerable – if true, then listed in loops, otherwise not listed.
3. configurable – if true, the property can be deleted and these attributes can be modified,
otherwise not.

We didn’t see them yet, because generally they do not show up. When we create a property “the
usual way”, all of them are true. But we can change them anytime.
Objects – Property flags and descriptors
How to get Property flag
let user = {name: "John"}
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');

The returned value is a so-called “property descriptor” object: it


contains the value and all the flags.
console.log(descriptor);
{
configurable: true,
enumerable: true,
value: "John“,
writable: true
}
Objects – Property flags and descriptors
How to set Property flag
To change the flags, we can use Object.defineProperty.
Syntax: Object.defineProperty(obj, propertyName, descriptor)
let user = {};
Object.defineProperty(user, “age", {value: 22, writable: false});
let descriptor = Object.getOwnPropertyDescriptor(user, ‘age');

console.log( JSON.stringify(descriptor ) );
{
"value": "John","writable": false,"enumerable": false,"configurable": false
}
Objects – Property value shorthand
• In real code we often use existing variables as values for property
names. For instance:

With same Name Short Hand


function makeUser(name, age) { function makeUser(name, age) {
return { return {
name: name, name, // same as name: name
age: age age // same as age: age
// ...other properties // ...
}; };
} }

let user = makeUser("John", 30);


alert(user.name); // John
Objects Methods and this keyword
Object Method this Keywords
let user = { let user = {
name: "John", name: "John",
age: 30 age: 30,
}; sayHi() {
user.sayHi = function() { console.log(this.name);
console.log("Hello!"); }
}; };
user.sayHi(); // Hello! user.sayHi(); // John
Object methods reuse with call and apply
Call() Method
• The call() method is a predefined JavaScript method
• With call(), an object can use a method belonging to another object.
Object methods reuse with call
Call() Method
var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}

var person1 = {
firstName:"John",
lastName: "Doe"
}

var person2 = {
firstName:"Mary",
lastName: "Doe"
}

person.fullName.call(person1); // Will return "John Doe"


Object methods reuse with call
Call() Method with arguments

var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}

var person1 = {
firstName:"John",
lastName: "Doe"
}

person.fullName.call(person1, "Oslo", "Norway");


Object methods reuse with apply
apply() Method
The apply() method is similar to the call() method (previous chapter).

var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}

var person1 = {
firstName: "Mary",
lastName: "Doe"
}

person.fullName.apply(person1); // Will return "Mary Doe"


Object methods reuse with call
apply() method with arguments
The apply() method accepts arguments in an array:
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}

var person1 = {
firstName:"John",
lastName: "Doe"
}

person.fullName.apply(person1, ["Oslo", "Norway"]);


The Difference Between call() and apply()
• The call() method takes arguments separately.

• The apply() method takes arguments as an array.

• The apply() method is very handy if you want to use an


array instead of an argument list.

You might also like