Assembly in Progress...

Objects in JavaScript

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 new keyword.

It looks like this: 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";
We can also create an object on the fly using a function.
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 type and the object's context

  • 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.

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 object
  • this 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 of this 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 for this.
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

There are two ways to dynamically set property names:
  • 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.
↓ Examples ↓
// 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.
↓ Examples ↓
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

delete returns true if it can delete the property and false if not. Example: Before delete: "name" = An object for Examples
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
// }
Object.entries(object) will create an array of property name-value nested arrays.
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."]
For-in loop can be used to iterate through each property name.
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
Object.keys() will grab all of the keys.
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"]
someObject.propertyIsEnumerable(): Added properties will be enumerable, while built-in properties will not be. proprtyIsEnumerable will tell both if a property is there and it is enumerable by returning a boolean
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 get and set work similar to methods. These provide access to retrieve or set properties that you may want to manipulate before completing the task or that you may not want to expose directly. For instance, credit card numbers or other sensitive information can be protected in this manner.

NOTE: property keys that should not be directly accessed generally should start with an underscore like: _name
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

defineProperty(someObject, property, {attribute definitions}) : You can add and alter property attributes, like whether the property is configurable, enumerable, etc. You can even create custom get and set methods. These custom methods give us control over each time the value of the property is set or retrieved

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 defineProperties().

// 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 Object.seal(object1) method prevents new properties from being added to it and sets all existing properties to non-configurable. Values of present properties can still be changed as long as they are writable.

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

Object.isSealed(object)

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 Object.freeze(object), a frozen object can no longer be changed. This means it will prevent:

  • 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.
Object.freeze() always returns the same object that was passed in.

We can check if an Object is frozen using .isFrozen(object)

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

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Post Navigation

q
↑ Back to Top