# Object
Objects have properties and methods associated with them.
An example of an array of objects.
```javascript
const technologyStacks = [
{
role: 'iOS Developer',
userInterface: ['UIKit', 'SwiftUI'],
codingPlatform: ['Xcode', 'AppCode'],
languages: ['Swift', 'Objective-C'],
backend: ['Firebase', 'Realm']
},
{
role: 'Full-Stack Web Developer',
userInterface: ['React, CSS, HTML'],
codingPlatform: ['Visual Studio Code', 'WebStorm'],
languages: ['JavaScript', 'TypeScript'],
backend: ['Express', 'Node', 'PostgresSQL']
}
]
```
## 1. Creating objects using object literal
```javascript
const fellow = {
// properties
name: 'Brian',
stack: 'iOS',
isMentor: true,
// methods
info: function() {
console.log(`Hi my name is ${this.name}.`)
}
};
console.log(fellow.stack); // iOS
fellow.info(); // Hi my name is Brian.
```
## 2. Creating objects using constructors
```javascript
const book = new Object();
book.title = '1984';
book.author = 'George Orwell';
book.isAvailable = false;
book.checkIn = function() {
this.isAvailable = true;
};
book.checkOut = function() {
this.isAvailable = false;
};
console.log(typeof book); // object
book.checkIn();
book.isAvailable // true
```
## 3. Accessing object properties
#### Dot Notation
```javascript
console.log(book.title);
```
#### Bracket Notation
```javascript
const value = book['title'];
console.log(value);
```
## 4. Accessing methods
```javascript
book.checkIn // [Function: checkIn]
// invoke (call) the checkIn function
book.checkIn();
book['checkin'];
```
## 5. The `this` keyword (context)
```javascript
const language = {
name: 'Swift',
platform: 'iOS',
currentVersion: 5.2,
update: function() {
this.currentVersion = 5.3; // refers to the property `currentVersion`
return this; // refers to the object instance
}
}
console.log(language.update()); // prints language object
/*
{
name: 'Swift',
platform: 'iOS',
currentVersion: 5.3,
update: [Function: update]
}
*/
```
#### Global `this`
The `this` global context in a Node environment and Browser environment varies.
Example of running `this` in a `repl.it` environment provides the following output
`this` global output
```javascript
{
console: {
log: [Function: log],
warn: [Function: warn],
dir: [Function: dir],
time: [Function: time],
timeEnd: [Function: timeEnd],
timeLog: [Function: timeLog],
trace: [Function: trace],
assert: [Function: assert],
clear: [Function: clear],
count: [Function: count],
countReset: [Function: countReset],
group: [Function: group],
groupEnd: [Function: groupEnd],
table: [Function: table],
debug: [Function: debug],
info: [Function: info],
dirxml: [Function: dirxml],
error: [Function: error],
groupCollapsed: [Function: groupCollapsed],
Console: [Function: Console],
profile: [Function: profile],
profileEnd: [Function: profileEnd],
timeStamp: [Function: timeStamp],
context: [Function: context]
},
alert: [Function: log],
prompt: [Function: prompt],
confirm: [Function: confirm],
module: Module {
id: '.',
path: '/home/runner/JavaScript-Playgrounds',
exports: {},
parent: null,
filename: '/home/runner/JavaScript-Playgrounds/index.js',
loaded: false,
children: [],
paths: [
'/home/runner/JavaScript-Playgrounds/node_modules',
'/home/runner/node_modules',
'/home/node_modules',
'/node_modules'
]
},
require: [Function: bound ],
__dirname: '/home/runner/JavaScript-Playgrounds',
__filename: '/home/runner/JavaScript-Playgrounds/index.js',
global: {
console: {
log: [Function: log],
warn: [Function: warn],
dir: [Function: dir],
time: [Function: time],
timeEnd: [Function: timeEnd],
timeLog: [Function: timeLog],
trace: [Function: trace],
assert: [Function: assert],
clear: [Function: clear],
count: [Function: count],
countReset: [Function: countReset],
group: [Function: group],
groupEnd: [Function: groupEnd],
table: [Function: table],
debug: [Function: debug],
info: [Function: info],
dirxml: [Function: dirxml],
error: [Function: error],
groupCollapsed: [Function: groupCollapsed],
Console: [Function: Console],
profile: [Function: profile],
profileEnd: [Function: profileEnd],
timeStamp: [Function: timeStamp],
context: [Function: context]
},
alert: [Function: log],
prompt: [Function: prompt],
confirm: [Function: confirm],
module: Module {
id: '.',
path: '/home/runner/JavaScript-Playgrounds',
exports: {},
parent: null,
filename: '/home/runner/JavaScript-Playgrounds/index.js',
loaded: false,
children: [],
paths: [Array]
},
require: [Function: bound ],
__dirname: '/home/runner/JavaScript-Playgrounds',
__filename: '/home/runner/JavaScript-Playgrounds/index.js',
global: [Circular],
clearInterval: [Function: clearInterval],
clearTimeout: [Function: clearTimeout],
setInterval: [Function: setInterval],
setTimeout: [Function: setTimeout] {
[Symbol(nodejs.util.promisify.custom)]: [Function]
},
queueMicrotask: [Function: queueMicrotask],
clearImmediate: [Function: clearImmediate],
setImmediate: [Function: setImmediate] {
[Symbol(nodejs.util.promisify.custom)]: [Function]
},
checkForGlobalThis: [Function: checkForGlobalThis]
},
clearInterval: [Function: clearInterval],
clearTimeout: [Function: clearTimeout],
setInterval: [Function: setInterval],
setTimeout: [Function: setTimeout] {
[Symbol(nodejs.util.promisify.custom)]: [Function]
},
queueMicrotask: [Function: queueMicrotask],
clearImmediate: [Function: clearImmediate],
setImmediate: [Function: setImmediate] {
[Symbol(nodejs.util.promisify.custom)]: [Function]
},
checkForGlobalThis: [Function: checkForGlobalThis]
}
```
#### Compare `this` context using `globalThis`
```javascript
function checkForGlobalThis() {
return this; // `this` here is bound to the `global` scope
}
const person = {
name: 'Kate',
info: function() {
return this; // does refer to the global context but refers to the object instance
}
}
console.log(checkForGlobalThis() === globalThis); // true
console.log(person.info() === globalThis); // false
```
## 6. Accessing ALL the `key, value` pairs of an Object using `Object.entries()`
> MDN documentation: The Object.entries() method returns an array of a given object's own enumerable string-keyed property [key, value] pairs, in the same order as that provided by a for...in loop. (The only important difference is that a for...in loop enumerates properties in the prototype chain as well).
> The order of the array returned by Object.entries() does not depend on how an object is defined. If there is a need for certain ordering, then the array should be sorted first, like Object.entries(obj).sort((a, b) => b[0].localeCompare(a[0]));.
[more on `Object.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries)
```javascript
const grades = {
adam: 85,
rachel: 90,
bob: 100,
cindy: 75
};
for (const [name, grade] of Object.entries(grades)) {
console.log(`${name} grade is ${grade}`);
}
/*
adam grade is 85
rachel grade is 90
bob grade is 100
cindy grade is 75
*/
```
## 7. Pass-by-reference and Pass-by-value
```javascript
const nancy = {
name: 'Nancy'
}
const heather = {
name: 'Heather'
}
function update(fellow1, fellow2) {
fellow1 = { name: 'Tony' }; // changing the object itself doesn't change the insstance, pass-by-value
fellow2.name = "Alex"; // changing the properties changes the insstance properties, pass-by-reference
}
update(nancy, heather);
console.log(nancy); // { name: 'Nancy' }
console.log(heather); // { name: 'Alex' }
```
## 8. Traditional JavaScript constructor functions vs (ECMAScript 2015) or ES6 classes
> MDN documentation: Prototypes are the mechanism by which JavaScript objects `inherit` features from one another.
#### A prototype-based language ?
> MDN documentation: JavaScript is often described as a prototype-based language — to provide inheritance, objects can have a prototype object, which acts as a template object that it inherits methods and properties from.
> An object's prototype object may also have a prototype object, which it inherits methods and properties from, and so on. This is often referred to as a `prototype chain`, and explains why different objects have properties and methods defined on other objects available to them.
## 9. Constructor functions
#### `Person` constructor function
```javascript
// Here we are using upppercase to denote that Person is a type as opposed to a function person() - good convention practice with naming
function Person(first, last, age, gender, interests) {
// property and method definitions
this.name = {
'first': first,
'last': last
}
this.age = age;
this.gender = gender;
}
```
#### Creating a `Person` instance using the constructor above
```javascript
const person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
```
The `Person` instance prototype object also inherits from the `Object.prototype` so methods such as `valueOf`, `toString` are available to it.
#### Printing `valueOf` on `person1`
```javascript
console.log(person1.valueOf());
/*
Person {
name: { first: 'Bob', last: 'Smith' },
age: 32,
gender: 'male'
}
*/
```
#### Providing our own `valueOf` will cause our version on the `person1` instance to be printed to the console
```javascript
function Person(first, last, age, gender, interests) {
// property and method definitions
this.name = {
'first': first,
'last': last
}
this.age = age;
this.gender = gender;
this.valueOf = function() {
console.log(`The person\'s age is ${age}`);
}
}
```
```javascript
console.log(person1.valueOf());
// The person's age is 32
```
#### Modifying prototyeps
```javascript
Person.prototype.bio = function(job) {
this.job = job;
console.log(`Hi, my name is ${this.name.first} and I work as a ${this.job}.`);
};
person1.bio('Full-Stack developer'); // now the `Person` object has a bio() method associated with all it's instances
// Hi, my name is Bob and I work as a Full-Stack developer.
```
## 10. ES6 classes
```javascript
class Venue {
constructor(name, location) { // similar to an initializer in Swift
this.name = name;
this.location = location
}
info() { // class method in JavaScript or instance method in Swift
console.log(`${this.name} is located in ${this.location}.`);
}
}
// now we can use the `new` keyword to create an instance of Venue()
const arthurAsheStadium = new Venue('Arthur Ashe', 'Flushing Meadows, NY');
arthurAsheStadium.info();
// Arthur Ashe is located in Flushing Meadows, NY
```
#### TODO: inheritance using the `extends` keyword
## 11. Challenges
#### Challenge 1
The Recipe Card
Never forget another recipe!
* Create an object to hold information on your favorite recipe. It should have properties for title (a string), servings (a number), and ingredients (an array of strings).
* On separate lines (one console.log statement for each), log the recipe information so it looks like:
* Mole
* Serves: 2
* Ingredients:
* cinnamon
* cumin
* cocoa
Solution
```javascript
const recipe = {
title: 'Strawberry Cake',
servings: 8,
ingredients: ['Flour', 'Butter', 'Strawberries', 'Sugar']
}
for (const [key, value] of Object.entries(recipe)) {
if (key === 'title') {
console.log(value);
}
if (key === 'servings') {
console.log(`Servings: ${value}`);
}
if (key === 'ingredients') {
console.log('Ingredients:')
for (const ingredient of value) {
console.log(ingredient);
}
}
}
/*
Strawberry Cake
Servings: 8
Ingredients:
Flour
Butter
Strawberries
Sugar
*/
```
***
#### Challenge 2
Write a JavaScript program to list the properties of a JavaScript object.
Sample object:
```javascript
const student = {
name : "David Rayy",
sclass : "VI",
rollno : 12
};
_Sample Output: [ 'name', 'sclass', 'rollno' ]_
const student = {
name : "David Rayy",
sclass : "VI",
rollno : 12
};
console.log(Object.keys(student));
```
Solution
```swift
const student = {
name : "David Rayy",
sclass : "VI",
rollno : 12
};
console.log(Object.keys(student)); // [ 'name', 'sclass', 'rollno' ]
```
***
#### Challenge 3
Create a class called `Person` which accepts the name of a person as a string, and his/her age as a number.
The Person class should have a method called describe which returns a string with the following syntax: "name, age years old". So for example, if John is 19 years old then the function describe of his object will return "John, 19 years old".
Solution
```javascript
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
describe() {
return `${this.name}, ${this.age} years old.`
}
}
const george = new Person('George', 29);
george.describe(); // George, 29 years old.
```
***
#### Challenge 4
The Reading List
Keep track of which books you read and which books you want to read!
* Create an array of objects, where each object describes a book and has properties for the title (a string), author (a string), and alreadyRead (a boolean indicating if you read it yet).
* Iterate through the array of books. For each book, log the book title and book author like so: "The Hobbit by J.R.R. Tolkien".
* Now use an if/else statement to change the output depending on whether you read it yet or not. If you read it, log a string like 'You already read "The Hobbit" by J.R.R. Tolkien', and if not, log a string like 'You still need to read "The Lord of the Rings" by J.R.R. Tolkien.'
Solution
```javascript
const readingList = [
{ title: 'Good to Great', author: 'Jim Collins', alreadyRead: false },
{ title: 'Unbroken', author: 'Laura Hillenbrand', alreadyRead: true },
{ title: 'Next', author: 'Michael Crichton', alreadyRead: true }
]
for (const book of readingList) {
const message = (book.alreadyRead) ? 'You already read' : 'You still need to read';
console.log(`${message} \"${book.title}\" by ${book.author}.`);
}
/*
You still need to read "Good to Great" by Jim Collins.
You already read "Unbroken" by Laura Hillenbrand.
You already read "Next" by Michael Crichton.
*/
```
***
#### Challenge 5
Write a function called `cashRegister` that takes a shopping cart object. The object contains item names and prices (itemName: itemPrice). The function should return the total price of the shopping cart.
```javascript
Example
// Input
const cartForParty = {
banana: '1.25',
handkerchief: '.99',
tShirt: '25.01',
apple: '0.60',
nalgene: '10.34',
proteinShake: '22.36'
};
// Output
cashRegister(cartForParty)); // 60.55
```
Solution
```javascript
function cashRegister(shoppingCart) {
let totalPrice = 0;
for (let [itemName, price] of Object.entries(shoppingCart)) {
price = parseFloat(price);
totalPrice += price;
}
return totalPrice;
}
const cartForParty = {
banana: '1.25',
handkerchief: '.99',
tShirt: '25.01',
apple: '0.60',
nalgene: '10.34',
proteinShake: '22.36'
};
let totalPrice = cashRegister(cartForParty);
console.log(`The total price of the shopping cart is ${totalPrice}`);
// The total price of the shopping cart is 60.55
```
***
#### Challenge 6
Write a class `Vec` that represents a vector in two-dimensional space.
It takes x and y parameters (numbers), which it should save to properties of the same name.
Give the Vec prototype two methods, `plus` and `minus`,
that take another vector as a parameter and return a new vector
that has the sum or difference of the two vectors’ (`this` and the parameter) x and y values.
Add a getter property `length` to the prototype that computes the length of the vector—that is,
the distance of the point (x, y) from the origin (0, 0).
```javascript
// Your code here.
console.log(new Vec(1, 2).plus(new Vec(2, 3)));
// → Vec{x: 3, y: 5}
console.log(new Vec(1, 2).minus(new Vec(2, 3)));
// → Vec{x: -1, y: -1}
console.log(new Vec(3, 4).length);
// → 5
```
Solution
```javascript
class Vec {
constructor(x,y) {
this.x = x;
this.y = y;
}
get length() {
return Math.sqrt((this.x * this.x) + (this.y * this.y));
}
plus(vec) {
return new Vec(this.x + vec.x, this.y + vec.y)
}
minus(vec) {
return new Vec(this.x - vec.x, this.y - vec.y)
}
}
console.log(new Vec(1, 2).plus(new Vec(2, 3))); // Vec { x: 3, y: 5 }
console.log(new Vec(1, 2).minus(new Vec(2, 3))); // Vec { x: -1, y: -1 }
console.log(new Vec(3, 4).length); // 5
```
***
#### Challenge 7
Define a `repeatify` function on the `String` object. The function accepts an integer that specifies how many times the string has to be repeated. The function returns the string repeated the number of times specified. For example:
```javascript
console.log('hello'.repeatify(3));
```
Should print `hellohellohello`.
Solution
```javascript
String.prototype.repeatify = function(times) {
let str = '';
for (let index = 0; index < times; index++) {
str += this;
}
return str;
}
'Alex is coding......'.repeatify(3);
/*
Alex is coding......Alex is coding......Alex is coding......
*/
```
***
## 12. Resources
1. [MDN - Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
1. [Stackoverflow - Is JavaScript a pass-by-reference or pass-by-value language?](https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language)