Basics
- Objects are the center of JS programming.
- Objects are lists or collections of methods and properties.
- For each property, objects always have a name (string) and a value that can be a string, number or function.
Object Creation: "new" Keyword
For us users, we can allocate the needed memory by simply using the
let variable = new Object()
↓ Examples ↓
Object creation: -new Object();:
const myObject = new Object();
myObject.title = "Js Object One";
myObject.description = "a cool new object to build and use.";
myObject.category = "UI Technology";
function myObjectCreator(title, description) {
this.title = title;
this.description = description;
// Adding methods
this.addACategory = addingTheCat;
this.displayObject = displayMyObject;
}
// The method to add the category
function addingTheCat(category) {
this.category = category;
}
// The method to display the object
function displayMyObject() {
return 'Title: ' + this.title + ' | Description: ' + this.description + ' | Category: ' + this.category + ' ';
}
const myObject2 = new myObjectCreator('Object 2', 'Custom description')
// Use the methods now built into the object.
console.log(myObject2.addACategory('Category 1'));
console.log(myObject2.displayObject());
// RESULT: "Title: Object 2 | Description: Custom description | Category: Category 1 "
Object Creation: Literal Constructor
It is possible, and likely most common, to create an object using literal syntax.let myObject3 = {}
myObject3 = {
title: "Object 3",
description: "This was made with a Literal Constructor",
displayDetails: function() {
return 'This is ' + this.title + ' | ' + this.description + '.';
}
}
console.log(myObject3.displayDetails());
// RESULT: "This is Object 3 | This was made with a Literal Constructor."
Singleton Object
A "Singleton" object is made only once. It may be used many times, but no other versions are created. In the following example, the ES6 syntax is used with Classes, const and Object.freeze() to create and keep a singleton object.class LoggedInUser {
constructor(firstName, lastName, password) {
if (LoggedInUser._instance) {
return LoggedInUser._instance
}
LoggedInUser._instance = this;
this.name = firstName,
this.last = lastName,
this.password = password
}
}
const userOne = new LoggedInUser('Han', 'Solo', 'WookiesEatTooMuch')
// Because this is a singleton, this will only reference userOne
const userTwo = new LoggedInUser('Darth', 'Vader', 'BeingEvilMakesMeSad')
console.log(userOne === userTwo)
console.log('userOne:', userOne.name, userOne.last, userOne.password);
// RESULT: "userOne: Han Solo WookiesEatTooMuch"
// Now, userTwo tried to create Darth Vader, but really this refernences userOne
console.log('userTwo:', userTwo.name, userTwo.last, userTwo.password);
// RESULT: "userTwo: Han Solo WookiesEatTooMuch"
Clear an object from memory
When an object will no longer be used, or at the end of an app, you can clear the object from memory. JavaScript has a process that automatically handles memory, but this is not always the most efficient process.
// Clearing memory is just setting to null
myObject3 = null;
singletonObject = null;
Advanced Object Concepts
Two Big Concepts: Type & Context
There are two significant concepts that should be understood when working with objects. these are the The object's
- Reference Type - An object is not a Primative type, like a string or number, but instead is a reference type, meaning it is a type created by the user. This means that, while it is possible to compare two numbers, for example, two different objects containing the exact same numbers will be a considered different types.
- context - An object's context refers to the object you are in at the time. It can be thought of as the object that is to the left of the dot when writing out: window.alert(). In this case, the
window object is the
context, or environment. It is what the
this keyword will refer to.
//////////////////////////
// Objects are Reference
// Types and so are never equal
//////////////////////////
// Compare two Primative types
3 === 3; // RESULT: true
// Compare two Reference types with the same numbers
[3] === [3]; // RESULT: false
// Now, pull out the number, a primative type and compare
[3][1] === [3][1]; // RESULT: true
Core Objects
Though the built-in JavaScript objects are not "advanced" concepts, understanding the group as a whole, their purposes and usage is a little outside of "basic" thinking.
- Array
x = new Array()
More detail HERE → - Date
x = new Date()
More detail HERE → - Error
x = new Error("Something went wrong")
More detail HERE → - Function
x = new Function("document.write("hello")")
More detail HERE → - RegExp
x = new RegExp("//d+")
More detail HERE → - this: Explained below ↓
The
this object
- In JavaScript
this is dynamically scoped, instead of lexical scope (like most of JavaScript). This means it is scoped to where it runs, not where it is written. With this, a function can be called by other objects and this will point to the object calling the function and not the original place it was written (lexical environment). - JavaScript's
this is an object that carries the parent object. this gives methods access to their objectthis will allow for executing the same code within a function.- TIP: When objects become nested, it can be difficult to follow where
this will refer to. It is easier to think ofthis as "Who called me?" When collapsing to one line, the answer to this question will be the object to the left "called me" and becomes the reference forthis .
const student = {
id: 1,
name: "Bob",
display: function() {
console.log('THIS id: ', this.id);
console.log('THIS name: ', this.name);
}
}
// "this" points to "student"
student.display();
// This next example uses one
// function that can point to
// the object calling it
function importantPerson() {
console.log('The name is', this.name, '.');
}
// Objects can now include the function
const obj1 = {
name: 'Cassy',
importantPerson: importantPerson
}
const obj2 = {
name: 'Jacob',
importantPerson: importantPerson
}
// "this" points to whatever the environment is
importantPerson(); // RESULT: -whatever the global invironment name is for your environment
// "this" points to "obj1"
obj1.importantPerson(); // RESULT: Cassy
// "this" points to "obj2"
obj2.importantPerson(); // RESULT: Jacob
Naming Props Dynamically
- It is possible use a variable, or even calculate numbers, to set the name. This would involve wrapping a variable or numbers in [ ].
- If the value and the name should be the same, you do not need to write this out. Simply writing the value or variable name will work.
// Using [ ]
const name = "Allissa Ryan";
const myObj = {
[name]: 'hello',
[1 + 2]: 'Just another string'
}
console.log(myObj) // RESULT: {
// 3: 'Just another string',
// 'Allissa Ryan': 'hello'
// }
// Using the shorthand
// for the name being
// the same as the value
const person1 = "Mario";
const pers1Member = true;
const pers1Stats = {
stat1: 10,
stat2: 43
}
const anotherObj = {
person1,
pers1Member,
pers1Stats
};
console.log(anotherObj);
// RESULT: { person1: 'Mario',
// pers1Member: true,
// pers1Stats: { stat1: 10, stat2: 43 }
// }
Inspecting Objects
Check for properties using:
in : will check if a given item in in the object.hasOwnProperty(): Has a given property local to the object.propertyIsEnumerable(): Property will be referenced in a loop.
const propCheckObject = {
name: 'An object for Examples',
date: new Date().toLocaleDateString(),
time: new Date().toLocaleTimeString(),
description: 'This objects description.'
}
// Check for a specific property in an object using IN:
console.log("name" in propCheckObject)
// returns true
// Check for a specific property, that was
// not inherited, in an object using hasOwnProprty()
console.log(propCheckObject.hasOwnProperty('toString'))
// returns false
// Check for enumerability
console.log(propCheckObject.propertyIsEnumerable('date'))
// returns true
Delete a Property
const student = {
id: 1,
name: "Bob",
display: function() {
console.log('THIS id: ', this.id);
console.log('THIS name: ', this.name);
}
}
// The object has a "name" property
console.log(student);
// RESULT: {
// display: f()
// id: 1
// name: "Bob"
// }
// We delete the "name" property
console.log(delete student.name)
// returns true
// The "name" property is gone
console.log(student);//
// RESULT: {
// display: f()
// id: 1
// }
const sampleObject = {
name: 'An object for Examples',
date: new Date().toLocaleDateString(),
time: new Date().toLocaleTimeString(),
description: 'This objects description.'
}
console.log(Object.entries(sampleObject))
// RESULT: [Array(2), Array(2), Array(2), Array(2)]
// 0: (2) ["name", "An object for Examples"]
// 1: (2) ["date", "5/22/2020"]
// 2: (2) ["time", "12:12:55 PM"]
// 3: (2) ["description", "This objects description."]
const sampleObject = {
name: 'An object for Examples',
date: new Date().toLocaleDateString(),
time: new Date().toLocaleTimeString(),
description: 'This objects description.'
}
for (property in sampleObject) {
console.log(`key= ${property}`)
}
// RESULT:
// name
// date
// time
// description
const sampleObject = {
name: 'An object for Examples',
date: new Date().toLocaleDateString(),
time: new Date().toLocaleTimeString(),
description: 'This objects description.'
}
console.log(Object.keys(sampleObject))
// RESULT: ["name", "date", "time", "description"]
const sampleObject = {
name: 'An object for Examples',
date: new Date().toLocaleDateString(),
time: new Date().toLocaleTimeString(),
description: 'This objects description.',
test: undefined
}
console.log(sampleObject.propertyIsEnumerable("date"))
// returns true
console.log(sampleObject.propertyIsEnumerable("length"))
// returns false as the property does not exist here
Accessor Properties
Accessor Properties
let creditCard = {
_name: "John",
get name() {
return this._name;
},
set name(value) {
this._name = value;
}
}
// Grab initial value
console.log(creditCard.name);
// RESULT: "John"
// Set the value to a new vue
creditCard.name = "New Data";
// The value is now the new value
console.log(creditCard.name);
// RESULT: "New Data"
Object Property Attributes
const creditCard = {
'name': 'No Name'
}
console.log(creditCard.propertyIsEnumerable("name")) // true
console.log(Object.name = 'Name One') // 'Name One'
Object.defineProperty(creditCard, 'name', {
value: 'Name Two',
writable: false,
enumerable: true,
});
console.log(creditCard.propertyIsEnumerable("name")); // false
console.log(Object.name = 'Name Two'); // 'Name Two'
console.log(Object.name = 'Name Three'); // 'Name Three'
Object.defineProperty(creditCard, 'name', {
get() {
return 'We addd this in our get() | ' + this._name;
},
set(value) {
this._name = value + ' | We add this in our set()';
}
});
console.log(creditCard.name = 'Name Four');
console.log(creditCard.name);
// We addd this in our get() | Name Four | We add this in our set()
Object.defineProperty(creditCard, 'name', {
configurable: false,
});
Object.defineProperty(creditCard, 'name', {
value: 'Name That Will Not Work'
});
// RESULT: An error because we just set this to configurable:no
Property attributes can be set like the following. This makes the property not enumerable(by default), not changeable(by default) and read only (because the set: function (){..} is not used).
Object.defineProperties(creditCard, "name", {
get: function() {
return return this._name;
}
})
Defining Multiple Properties with defineProperties()
We can define multiple properties all at once using
// Create the object.
let creditCard = {}
// Set the property attributes
Object.defineProperties(creditCard, {
// Define object. By default, not enumerable or configurable or writable.
_name: {
value: "John",
enumerable: true,
configurable: true,
writable: true,
},
// Set acccessor properties.
name: {
get: function() {
return 'We addd this in our get() | ' + this._name;
},
set: function() {
this._name = value + ' | We add this in our set()';
},
// can set enumerable and configurable here.
enumerable: true,
configurable: true,
},
_password: {
value: "password123",
enumerable: true,
configurable: false,
writable: true,
}, //
// Set acccessor properties.
password: {
get: function() {
return 'We addd this in our get() | ' + this._password;
},
set: function() {
this._password = value + ' | We add this in our set()';
},
// can set enumerable and configurable here.
enumerable: true,
configurable: true,
}
})
console.log(creditCard)
// RESULT:
// {
// name: (...)
// password: (...)
// _name: "John"
// _password: "password123"
// get name: ƒ ()
// set name: ƒ ()
// get password: ƒ ()
// set password: ƒ ()
// }
Retrieving Property Attributes
This will return a property descriptor for a property that is directly on an object and not in the object's prototype chain. Ultimately, this will grab attributes of properties local to the object.
Object.getOwnPropertyDescription(object, property)
let creditCard = {
name: "John"
};
let descriptor = Object.getOwnPropertyDescriptor(creditCard, "name"); // true
console.log(descriptor.enumerable); // true
console.log(descriptor.configurable); // true
console.log(descriptor.writable); // true
console.log(descriptor.value); //John
Managing Attribute Manipulation
Prevent extending an Object
Objects are, by default, able to be extended, which means they can be added to. Below shows how to prevent this and how to check for extensibility.
Object.preventExtentions(object)
const attribObject = {
name: "John"
};
// Make the object not extensible
Object.preventExtensions(attribObject);
// Try to add a property
Object.defineProperty(attribObject, 'age', {
value: "45"
});
// RESULT: error - "Cannot define property age,
// object is not extensible"
console.log(attribObject);
// RESULT: Returns only name: "John". "age" is not added
Check if an object is extensible using
Object.isExtensible(object)
This checks if an object is extensible or not. This will return true if it is extensible and false.
const attribObject2 = {
name: "John"
};
Object.preventExtensions(attribObject2)
console.log(Object.isExtensible(attribObject2));
// RESULT: false because we prevented extending
Seal an Object
The
const sealExampleObj = {
name: "Han"
};
console.log(sealExampleObj.name); // RESULT: "Han"
Object.seal(sealExampleObj)
sealExampleObj.name = "Leia";
console.log(sealExampleObj.name);
// RESULT: "Leia", becasue sealing does not stop changing values
console.log(delete sealExampleObj.name);
// RESULT: "false" becasue we cannot add or remove properties when sealed
console.log(sealExampleObj.name); // RESULT: "Leia" - It is still there
We can check if an Object is sealed using
This will check if an object is extensible or not and returns a true or false, accordingly.
console.log(Object.isSealed(sealExampleObj));
// RESULT: "true" because we sealed this in the prevcious example
Freeze an Object
Using
- new properties from being added to it.
- the values of properties from being changed.
- existing properties from being removed.
- any change to enumerability.
- the configurable setting from changing.
- manipulation of the writeable setting on existing properties.
- any change to the object's prototype.
We can check if an Object is frozen using
const sealExampleObj = {
name: "Han"
};
Object.freeze(sealExampleObj)
sealExampleObj.name = "Leia";
console.log(sealExampleObj.name);
// RESULT: "Han", becasue freezing stops changing values
console.log(delete sealExampleObj.name);
// RESULT: "false" becasue we cannot add or remove properties when sealed
console.log(sealExampleObj.name);
// RESULT: "Han" - The name property is stil there
console.log(Object.isFrozen(sealExampleObj));
// RESULT: "true" because we froze the onject here