# Day 1: JS Objects

## JS Objects

### Objects in Review

Let's visit a site most of you will probably be familiar with, [Amazon](https://www.amazon.com). If we type something to search for, you may notice all the results have similar properties. Things like, *price*, *title*, *reviews*, *Prime eligibility* and a *picture*.

In programming, we need a way to contain logic and data about things in the real world and represent them in our programs. An effective way to do this is with *objects*.

In JavaScript, **objects are collections of properties(key-value pairs)**. We can add, remove, or change these properties as we please. The simplest way to create an object is by using **object literal notation**.

```javascript
const car = {
  make: 'Honda',
  model: 'Civic',
  year: 1997, // Generally, there's no comma after the last pair!
};
```

> "make" is the key, while "Honda" is the value

> Objects must have both a key and a value - neither can be empty.

Objects are a complex data type - sometimes referred to as a dictionary/hash/map.

* They are a collection of key-value pairs called properties.
* Key-value pairs are separated by commas.
* The keys which we explicitly state when defining a property are analogous to our array indexes. They are how we access the associated value (more below).

In the above example, the variable `car` points to an object literal. This particular object has 3 properties: `make`, `model` and `year`.

We could store this same information in an array like this...

```javascript
const car = ['Honda', 'Civic', 1997];
```

What advantages might there be in storing `car` as an object?

#### Interacting with Objects

**Create**

We already saved a sample object to a `car` variable. We did this using **object literal notation**.

```javascript
const car = {
  make: 'Honda',
  model: 'Civic',
  year: 1997,
  'tire-type': 'Goodyear',
  // NOTE: Keys with a "-" or space in their name must be surrounded by quotation marks.
  // NOTE: You should use camelCase in JS, but sometimes you need to work with hyphens in JSON objects, if they were generated from a non-JavaScript API.
};
```

**Read**

To access object properties, we use either dot `.property` or bracket `['property']` notation.

```javascript
console.log( car.make )
console.log( car['make'] )

// What happens when we try to access a property yet to be defined?
console.log( car.owner )

// NOTE: When accessing properties whose keys have a "-" or space in them, you must use bracket notation.
console.log( car['tire-type'] )

// NOTE: When accessing properties with a variable, you must also use bracket notation
function(carProp) {
  car[carProp]
}
```

Dot notation is much more common than bracket notation. Why might that be?

**Update**

Call on the object property just like we did when reading it, and use the assignment operator `=` followed by its new value.

```javascript
car.year = 2003;
// or
car['year'] = 2003;
```

We can also create brand new properties for an object after it's initialized using this method.

```javascript
// Now our car has a smell property equal to "Leathery Boot". We did not initially declare this property.
car.smell = 'Leathery Boot';

console.log(car);
```

**Delete**

If you want to delete an object property entirely, use the `delete` keyword.

* This deletes the whole key-value pair, not just the value.
* You won't do this often.

```javascript
delete car.smell;
```

**Iterating through an Object**

Like arrays, you can use a loop to iterate through an object. Say we want to print out all of an object's keys...

This is called a `for in` loop

```javascript
// Iterate through object keys
for (key in car) {
  console.log(key);
}
```

> Knowing this, how could we go about getting all the values in an object?

JavaScript objects also have native methods that take care of this for us...

```javascript
// .keys()
Object.keys(car);
// .values()
Object.values(car);
// key-value pairs
Object.entries(car);
```

### Methods

Methods are functions that are attached to some object.

```javascript
// Our car now has a drive method...
const car = {
  make: 'Honda',
  model: 'Civic',
  color: 'red',
  drive: function () {
    console.log('vroom vroom');
  },
  gears: ['Reverse', 'Neutral', '1', '2', '3', '4'],
  engine: {
    horsepower: '6 horses',
    pistons: 12,
    fast: true,
    furious: false,
  },
  // Methods can take arguments
  gps: function (location) {
    console.log(`Beep boop, driving to ${location}`);
  },
};

// We can run the car's two methods like so...
car.drive();
car.gps('neverland');
```

Checkout our awesome souped-up car! With methods as part of our JavaScript toolbox, we now have an interface with which we can interact with our objects.

> We've only scratched the surface for objects. We'll dive a bit deeper into them later. If you're looking for more on the power of objects and functions, we recommend reading [The Secret Life of JS Objects](http://eloquentjavascript.net/06_object.html) chapter in Eloquent JS

## Context

### What is Context?

In JavaScript, context tells us where functions are invoked.

In short, the **context is the object that a function is attached to**. We'll see that context can change under certain circumstances.

Every time a JavaScript function is called, a context is determined / set. That context is always an object, and can be referenced in the function definition using a special keyword in JS, `this`.

We use `this` similar to the way we use pronouns in natural languages like English and French. Say we write:

```
John bites an apple. The apple tastes good
```

We can also say it another way:

```
John bites an apple. This tastes good
```

What does `this` refer to?\` The apple.

In a similar manner, we use the `this` keyword as a replacement for the subject in question.

#### `this` in an Object

Here's an example of the most common way context is determined for a function. When a method is called on an object, that object becomes the context...

```javascript
const user = {
  fullName: 'James Reichard',
  sayName: function () {
    console.log(`My name is ${this.fullName}.`);
  },
};
user.sayName();
```

<details>

<summary><strong>What does <code>this</code> represent here?</strong></summary>

Here the object that the method is being called on is `user`

</details>

#### 'Getting' Properties using `this`

```javascript
const user = {
  fullName: 'James Reichard',
  favoriteFood: 'Rice pudding',
  sayName: function () {
    console.log(`My name is ${this.fullName}.`);
  },
  sayHello: function () {
    console.log(
      `Hi my name is ${this.fullName} and my favorite food is ${this.favoriteFood}.`
    );
  },
};

user.sayHello(); // for this function invocation, `this` is `user`
```

#### 'Setting' Properties using `this`

This feature allows not just 'getting' property info on objects, but also setting properties. Consider this example:

```javascript
const user = {
  userName: 'numbr1rawkr',
  isSignedIn: false,
  signIn: function () {
    this.isSignedIn = true;
  },
  signOut: function () {
    this.isSignedIn = false;
  },
};

user.signIn();
user.isSignedIn; // => true
user.signOut();
user.isSignedIn; // => false
```

*But what if we want more control?*

Because we've written a method to set the `isSignedIn` property, we can use that method to provide more control. For example... what if we wanted to check a user's password before letting them sign in?

```javascript
const user = {
  userName: 'numbr1rawkr',
  password: 'password1234',
  isSignedIn: false,
  signIn: function (pwd) {
    if (pwd === this.password) {
      this.isSignedIn = true;
    }
  },
  signOut: function () {
    this.isSignedIn = false;
  },
};

user.signIn('tacobell');
user.isSignedIn; // => false
user.signIn('password1234');
user.isSignedIn; // => true
user.signOut();
user.isSignedIn; // => false
```

#### 'Running' methods using `this`

We can also use `this` to reference and call other methods on the object.

```javascript
const user = {
  userName: "numbr1rawkr",
  password: "password1234",
  isSignedIn: false,
  signIn: function(pwd) {
    if(pwd === this.password) {
      this.isSignedIn = true
      this.greetUser()
    }
  },
  signOut: function() {
    this.isSignedIn = false
  },
  greetUser: function() {
    console.log(`Welcome back ${this.userName}!`)
  }
}

user.signIn("tacobell")
user.isSignedIn // => false
user.signIn("password1234")
// => Welcome back numbr1rawkr
user.isSignedIn // => true
user.signOut()
user.isSignedIn // => false
-
```

#### Default Context

When a function is called, but it's not a method on an object, and no context is otherwise assigned (see later sections), then the context is set to the default context. In a browser, the default context is the `window` object.

```javascript
function revealThis() {
  console.log(this);
}

revealThis();
```

#### A Rule of Thumb

In general, `this` is probably the **parent** or enclosing item (item being function or object)

Some exceptions are:

* In an event listener function, `this` is the thing where the event originated (such as the button that was clicked).
* In another callback function, in which case `this` is probably the `window`.
* When `.bind()` is used to change the context manually.

When in doubt, log it out...

```javascript
console.log(this);
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ga0-2.gitbook.io/seifxr10anz-content/week-3/day-1-js-objects.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
