JavaScript: Objects

Object Literal

Data types in JavaScript
There are 8 data types in JavaScript.
7 data types are primitives
  • undefined
  • null
  • boolean
  • number
  • bigint
  • string
  • symbol
They are called primitives because they can only contain a single thing.
Object: 8th data type - Not a primitive
It is used to store keyed collections of carious data and more complex entities.
There are many kinds of objects.
For example:
  • Plain object, or just Object (this chapter)
  • Array
  • Date
  • Error
Some people will there are date type and array type. But they don't formally have their own data type. they are object
Object literal
Imagine object as a box with a list of informations inside. Each information is stored inside a labeled folder.
object
label value
label value
label value
user
name kitty
age 3
is cat true
  • Object: the box
  • Property: the folder name - information combo
  • Property name / key: the folder name
  • Property value: the information inside
Object literal
We called this kind of object object literal: we literally write out the object contents as we create it.
This is different from objects instantiated from classes. Will learn about it later.

Object Property

Object property
key: value,
A property is a key: value pair
  • key/identifier - property name (a string)
  • value - the value (can be anything)
Creating empty object
let obj = {};             // "Object literal" syntax - commonly used
let obj = new Object();   // "Object constructor" syntax
Creating object with properties
let obj = {
    propName1   : propVal1,
    propName2   : propVal2,
    "prop name3": propVal3
};
let user = {
    name    : "Kitty",
    age     : 3,
    "is cat": true
};
A figure bracket {...} containing an optional list of properties.
Multiple words as property name
  • Property name can be mutiple words.
  • The multiple words must be quoted: "prop name"
Hanging / trailing comma
  • Last property in the list might end with a comma even though it's not separating.
  • It makes it easier to add/remove/move around properties because all the lines are alike.
let obj = {
    propName1: propVal1,
    propName2: propVal2,
};
Key is unique, use only once
If the same key used more than once: the last value overrides the previous ones.
let user = {
    name: "Kitty",
    age: 3,
    name: "Doggie",
};

user;       // {name: 'Doggie', age: 3}

Accessing object: dot notation and square brackets

Accessing property values
2 ways:
  • dot notation
    • The key must be a valid variable identifier: contains no spaces, doesn't start with a digit, doesn't include special characters ($ and _ are allowed).
  • square [] bracket notation
    • The key can be any string. It must be written within quotation marks.
Multiple words property name
  • must use [] brackets and quotation marks, instead of dot notation.
obj.propName        // prop value
obj["propName"]     // prop value
obj["prop name"]    // prop value
user.name       // "Kitty"
user["name"]    // "Kitty"
user["is cat"]  // true
Don't forget the quotation mark when using the square brackets even property name is 1 word. Without, it won't work. The use without quotation mark is for variable names, not object property name.
user["name"]    // "Kitty"
user[name]      // undefined
Add property values
By accessing, using dot notation. The folder doesn't need to preexist.
obj.propName = propVal;
obj["propName"] = propVal;
user.isAdmin = true;
user["is admin"] = true;
Delete properties
By using delete operator.
delete obj.propName;
delete obj["propName"];
delete user.age;
delete user["is cat"];
Dot notation vs square brackets notation, which one to choose
  • Dot notation looks simpler and cleaner. It's preffered when possible.
  • Square brackets offers much more manipulations, for example when the property name will be assigned in the future. Use when needed.
  • Use square brackets when the property name is multiple words.

Square brackets

Square brackets [] notation
[] can take 2 forms of property name.
  • ["prop name"] - Property name itself (quoted string literal)
  • [key] - Key variable (not quoted)
let key = "is cat";
user[key] = true;

// The same as:
user["is cat"] = true;
As a variable key
  • Therefore [] provides a way to give a slot in the code, to be filled with chosen property name at a later time.
  • Since . can only take 1 form: .propName, it doesn't provide similar role. It doesn't have a way to attach a variable name. Must be the property name itself.
let user = {
    name    : "Kitty",
    age     : 3,
    "is cat": true
};

let key = prompt("Get name or age?", "name");

alert(user[key]);   // "Kitty" (if "name" is entered)

Object as an object property

Object as a property value
Property can be any value including an object.
let obj = {
    key1: {
        key1A: valueA,
        key1B: valueB,
    },
    key2: value2
}
Compare: Property is an array
let user = {
    name: ["Jane", "Doe"],
}

user;               // {name: (2) ['Jane', 'Doe']}
user.name;          // (2) ['Jane', 'Doe']

user.name[0];       // 'Jane'
user['name'][0]     // 'Jane'
Compare: Property is an object
Accessing the value can be done using chained dot notation or square brackets. Even combination.
let user = {
    name: {
        first: "Jane",
        last: "Doe",
    }
}

user;                   // {name: {first: 'Jane', last: 'Doe'}}
user.name;              // {first: 'Jane', last: 'Doe'}

user.name.first;        // 'Jane'
user['name']['first'];  // 'Jane'

user.name['first'];     // 'Jane'
user['name'].first;     // 'Jane'
Associative arrays
Accessing object value using [] looks like accessing array. Instead of using index, object is using "key".
arr[0]
obj["key"]
This is why sometimes objects are called associative array.

Computed properties

Computed properties
Using [] in an object literal when creating an object.
let key = prompt("Enter key name:", "keyName");

let obj = {
    [key]: value,
}

obj.keyName     // value
For example
let fruit = prompt("Which fruit to buy", "apple");

let bag = {
    [fruit]: 5,
}

bag;         // {apple: 5}
bag.apple;   // 5   
It's the same with
let fruit = prompt("Which fruit to buy", "apple");
let bag = {};
bag[fruit] = 5;

bag;         // {apple: 5}
We can modify the name further
let fruit = prompt("Which fruit to buy", "apple");

let bag = {
    [fruit + "Local"]: 5,
}

bag;         // {appleLocal: 5}

Property value shorthand

Making a property from a variable
function makeUser(name, age) {
    return {
        name: name,
        age: age,
    };
}

let user = makeUser("Kitty", 3);
user;  // {name: "Kitty", age: 3}
Property value shorthand
It's very common, it has a shorthand
function makeUser(name, age) {
    return {
        name,     // same as name:name
        age,      // same as age:age
    };
}

let user = makeUser("Kitty", 3);
user;  // {name: "Kitty", age: 3}
Normal properties and shorthands can be used at the same time
let user = {
    name,       // same as name:name
    age: 3
};

user;  // {name: "", age: 3}
If variable name has been filled, then it will be included in the object user.
let name = "Kila";
let user = {
    name,       // same as name:name
    age: 3
};

user;  // {name: "Kila", age: 3}

Property name limitations

Variable name limitation
  • Can't be language-reserved words, eg: for, let, return
Property name limitation
  • Can be language-reserved words, eg: for, let, return
  • Can be any strings or symbols
  • Other types can be used but automatically converted to strings. eg: number 0 becomes string "0"
  • Restriction: __proto__ can't be set to a non-object value.
    let obj = {};
    obj.__proto__ = 5;      // assign a number
    obj.__proto__;          // {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …} 
    

"In" operator

Non-existing property: undefined
In JavaScript (not in many other languages), it's possible to access any property, there's no error if the property doesn't even exist.
Non-existing property will return undefined. We can use this to identify if property exists.
obj.propName === undefined;

// true means property doesn't exist
// false means property exists
let pet = { name: "Kitten" }
pet.name === undefined;     // false
pet.type === undefined;     // true
"in" operator
in is used to check whether there's property "key" inside an object.
"key" in obj
let pet = { name: "Kitten" };
"name" in pet     // true
"type" in pet     // false
Be aware with the use of the quotation mark
let pet = { name: "Kitten" };
let prop = "name";

"name" in pet   // true
name in pet     // false
prop in pet     // true
"prop" in pet   // false
Why in exists? Isn't using === undefined enough?
Sometimes a property value is actually undefined. The property does exist.
let pet = { type: undefined };

pet.type;               // undefined (as if property type doesn't exist)
pet.type === undefined  // true (as if property type doesn't exist)
"type" in pet           // true (not ambiguos)
However this situation actually quote rare, because undefined should not be explicitely assigned. Instead of undefined, we are usually use null for unknown or empty values. So in practise maybe in is not often seen since === undefined is adequate.

The "for..in" loop

for..in syntax
for (key in obj) {
    ... key ...         // property name
    ... obj[key] ...    // property value
}
  • Common looping variable used: key, prop
  • The looping variable can be declared inside the loop
let user = {
    name: "Kitty",
    age: 3,
};

let keyArr = [];
let valArr = [];

for (let key in user) {
    keyArr.push(key);
    valArr.push(user[key]);
}

keyArr;     // (2) ['name', 'age']
valArr;     // (2) ['Kitty', 3]

Object: integer keys are ordered

There are some ordering happening in object
  • Integers are sorted
  • Others are in creation order
  • Integers are placed ahead of the others
let user = {
    2: "2 cats",
    name: "Kitty",
    "1": "1 cat",
    3: "3 cats",
};

user["0"] = "no cat";
user.age = 3;

let keyArr = [];
let valArr = [];

for (let key in user) {
    keyArr.push(key);
    valArr.push(user[key]);
}

user;     // {0: 'no cat', 1: '1 cat', 2: '2 cats', 3: '3 cats', name: 'Kitty', age: 3}
keyArr;   // (6) ['0', '1', '2', '3', 'name', 'age']
valArr;   // (6) ['no cat', '1 cat', '2 cats', '3 cats', 'Kitty', 3]
Positive sign or decimal doesn't qualify for this integer order.
let user = {
    "4": "4 cats",
    "2": "2 cats",
    "+3": "+3 cats",
    "3.2": "3.2 cats",
    "3": "3 cats",
};

let keyArr = [];
let valArr = [];

for (let key in user) {
    keyArr.push(key);
    valArr.push(user[key]);
}

user;     // {2: '2 cats', 3: '3 cats', 4: '4 cats', +3: '+3 cats', 3.2: '3.2 cats'}
keyArr;   // (5) ['2', '3', '4', '+3', '3.2']
valArr;   // (5) ['2 cats', '3 cats', '4 cats', '+3 cats', '3.2 cats']

Object methods

Object properties vs object methods
An object is a collection of related data and/or functionality. They consisted of several variables and functions. Inside an object:
  • Variables are called object properties
  • Functions are called object methods
Object property
propName: value,
Object method
methodName: function() {...this.key...},
// or
methodName() {...this.key...},
this.key
this.key
this.key is used to access data property from inside the function formula.
Inside an object
let obj = {
    propName: value,
    method1: function() {...this.propName...},
    method2() {...this.propName...}
}
Object method example
let user = {
    name: ["Bob", "Smith"],
    age: 15,
    fullName: function () {
        return `${this.name[0]} ${this.name[1]}`;
    },
    fakeAge() {
        return this.age + 5;
    },
}

user;               // {name: Array(2), age: 15, fullName: ƒ, fakeAge: ƒ}
user.name;          // (2) ['Bob', 'Smith']
user.name[0]        // 'Bob'
user.fullname;      // ƒ () {return `${this.name[0]} ${this.name[1]}`;}
user.fullname();    // 'Bob Smith'
user.fakeAge;       // ƒ fakeAge() {return this.age + 5;}
user.fakeAge();     // 20
Adding object method
It can be done similar way as adding object property, using dot or [] notation
let obj = {};
obj.propName = value;
obj.methodName = function () {...};
let user = {};
user.name = {first: "John", last: "Doe"};
user.fullname = function () {return `${this.name.first} ${this.name.last}`};

user.fullname();    // 'John Doe'

Constructor

Automatizing object creation
A function blueprint/template can be used to create multiple object of similar structure.
Without learning about constructor, this can be done using simple function.
However since this is a very typical operation, Constructors exist to make this routine even more simple and easy.
Creating objects using function without constructor
The creator function
function createPerson(name, age) {
    const obj = {};
    obj.name = name;
    obj.age = age;
    obj.greeting = function() {
        console.log(`Hi! I'm ${this.name}, ${this.age} years old.`);
    }
    return obj;
}
Entering the people
const yudi = createPerson("Yudi", 35);
const bobo = createPerson("Bobo", 15);
const mira = createPerson("Mira", 20);
Results
yudi;   // {name: 'Yudi', age: 35, greeting: ƒ}
bobo;   // {name: 'Bobo', age: 15, greeting: ƒ}
mira;   // {name: 'Mira', age: 20, greeting: ƒ}

yudi.greeting();   // Hi! I'm Yudi, 35 years old.
bobo.greeting();   // Hi! I'm Bobo, 15 years old.
mira.greeting();   // Hi! I'm Mira, 20 years old.
Constructor
  • Constructors named for the type of object we create and started with a capital letter.
  • Use this keyword to address the object.
  • Use new to call the function as a constructor.
Create the constructor
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.greeting = function() {
        console.log(`Hi! I'm ${this.name}, ${this.age} years old.`);
    }
}
Calling the constructor
const yudi = new Person("Yudi", 65);
const bobo = new Person("Bobo", 35);
const mira = new Person("Mira", 77);
Results
yudi;   // {name: 'Yudi', age: 65, greeting: ƒ}
bobo;   // {name: 'Bobo', age: 35, greeting: ƒ}
mira;   // {name: 'Mira', age: 77, greeting: ƒ}

yudi.greeting();   // Hi! I'm Yudi, 65 years old.
bobo.greeting();   // Hi! I'm Bobo, 35 years old.
mira.greeting();   // Hi! I'm Mira, 77 years old.

Exercises

isEmpty
let schedule = {};

function isEmpty(obj) {
    for (let key in obj) {
        return false;
    }
    return true;
}

isEmpty(schedule);  // true

schedule["8:30"] = "get up";
isEmpty(schedule);  // false
Sum salaries
let salaries = {
    John: 100,
    Ann: 160,
    Pete: 130
};

function sumVal(obj) {
    let sum = 0;
    for (let key in obj) {
        sum += obj[key];
    }
    return sum;
}

let sum = sumVal(salaries);
sum;        // 390
Multiply numeric by 2
let menu = {
    width: 200,
    height: 300,
    title: "My menu"
};

function multiply(obj){
    for (let key in obj) {
        if (!isNaN(obj[key])) {
            obj[key] = obj[key] *2;
        }
    }
}

multiply(menu);
menu;       // {width: 400, height: 600, title: 'My menu'}
Create object from user input
let key1 = prompt("Enter first key: ");
let val1 = prompt("Enter first value: ");
let key2 = prompt("Enter second key: ");
let val2 = prompt("Enter second value: ");

let user = {};
user[key1] = val1;
user[key2] = val2;

user;       // {name: 'John', age: '24'}
Band Info
let band = {
    name: "Bon Jovi",
    nationality: "USA",
    genre: "rock",
    members: 5,
    formed: 1983,
    split: false,
    album: [{
        name: "Slippery When Wet",
        released: 1986,
    }, {
        name: "Crush",
        released: 2000,
    }]
};
function isEnd(split) {
    if (split === false) {
        return ["s", "now"];
    } else {
        return ["d", split];
    }
}

const bandInfo = `${band.name} is a ${band.genre} band from ${band.nationality}. This ${band.members} members band active${isEnd(band.split)[0]} from ${band.formed} until ${isEnd(band.split)[1]}. Their succesful albums include ${band.album[0].name}, released ${band.album[0].released}, and ${band.album[1].name}, released ${band.album[1].released}.`

bandInfo;
// 'Bon Jovi is a rock band from USA. This 5 members band actives from 1983 until now. Their succesful albums include Slippery When Wet, released 1986, and Crush, released 2000.'

// If band.split = 2021, the bandInfo becoming:
// 'Bon Jovi is a rock band from USA. This 5 members band actived from 1983 until 2021. Their succesful albums include Slippery When Wet, released 1986, and Crush, released 2000.'

template

template
template

References