Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Objects and Object Constructors: Add examples of grouping functionality with objects #27381

Open
wants to merge 52 commits into
base: main
Choose a base branch
from
Open
Changes from 15 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
608cd00
Lint 'objects_and_object_constructors.md'
takinabradley Feb 16, 2024
e3e36f9
Add examples of how objects are useful both to organize data and to g…
takinabradley Feb 16, 2024
77d0a71
Fix spelling errors
takinabradley Feb 16, 2024
cfce9a2
Merge branch 'main' of github.com:TheOdinProject/curriculum into why_…
takinabradley Feb 18, 2024
d6366b5
Add additional examples of objects as a design pattern
takinabradley Feb 18, 2024
098d451
fix never-ending note
takinabradley Feb 18, 2024
9b9e4a1
small editorial changes
takinabradley Feb 18, 2024
4e581ea
update language to fit the topic of objects representing more abstrac…
takinabradley Feb 18, 2024
53bdcaa
Merge branch 'main' of github.com:TheOdinProject/curriculum into why_…
takinabradley Feb 26, 2024
f89e4c6
Merge branch 'main' of github.com:TheOdinProject/curriculum into why_…
takinabradley Feb 28, 2024
afef9e9
Merge branch 'main' of github.com:TheOdinProject/curriculum into why_…
takinabradley Mar 2, 2024
827614d
fix code tags, apostrophes, and spelling errors
takinabradley Mar 9, 2024
6c96f0c
Merge branch 'main' of github.com:TheOdinProject/curriculum into why_…
takinabradley Mar 9, 2024
9cb829e
remove unnecessary switchOn/switchOff logic
takinabradley Mar 9, 2024
a202e02
Merge branch 'main' of github.com:TheOdinProject/curriculum into why_…
takinabradley Jun 23, 2024
86c5ca7
Merge branch 'main' of github.com:TheOdinProject/curriculum into why_…
takinabradley Jul 1, 2024
b78f821
add a new lesson on organizing code with objects
takinabradley Jul 1, 2024
b0e07a5
remove language indicating object literals are the best way to create…
takinabradley Jul 1, 2024
3c0e23f
clarify what's meant by object literals not having a way to make priv…
takinabradley Jul 1, 2024
3f97244
remove object organization content to be extracted into a separate le…
takinabradley Jul 1, 2024
61e772d
change the lesson goal on the `this` keyword to be more general
takinabradley Jul 2, 2024
3ffb1a2
remove references to objects used in 'Organizing Code with Objects' l…
takinabradley Jul 2, 2024
4cad12f
change the assignment to use the easier devsage video
takinabradley Jul 3, 2024
19da94c
edit assignment wording so it doesn't feel as if it's the first time …
takinabradley Jul 3, 2024
d1ba7bf
Merge branch 'main' of github.com:TheOdinProject/curriculum into why_…
takinabradley Jul 10, 2024
9535e55
Fix new introduction to lesson
takinabradley Jul 10, 2024
73def3b
make small editorial changes
takinabradley Jul 23, 2024
86f8992
add lesson exercises
takinabradley Jul 23, 2024
2e2246f
Make the 'objects as machines' subsection clearer
takinabradley Jul 23, 2024
16cbddf
Split long paragraph into two
takinabradley Jul 23, 2024
e5be024
Merge branch 'main' of github.com:TheOdinProject/curriculum into why_…
takinabradley Jul 29, 2024
61e1d38
Merge branch 'main' of github.com:TheOdinProject/curriculum into why_…
takinabradley Aug 21, 2024
28c8b5a
fix unescaped underscores
takinabradley Aug 21, 2024
88275cb
Merge branch 'main' of github.com:TheOdinProject/curriculum into why_…
takinabradley Sep 21, 2024
a93de3c
Merge branch 'main' of github.com:TheOdinProject/curriculum into why_…
takinabradley Oct 12, 2024
e7c08dd
Rearrange introductory content with editorial changes.
takinabradley Oct 12, 2024
965e479
prefix dashes with spaces
takinabradley Oct 12, 2024
1da76cc
fix spelling error
takinabradley Oct 12, 2024
cf99f6a
small editorial change
takinabradley Oct 12, 2024
c7d0270
Small editorial change
takinabradley Oct 12, 2024
d46a1f0
Fix heading case to conform to style guide
takinabradley Oct 12, 2024
65a5b44
Supply accessable link
takinabradley Oct 12, 2024
af9ce68
Add period at end of assignment
takinabradley Oct 12, 2024
218d97a
Describe how knowing what methods/properties should be on an objects …
takinabradley Oct 12, 2024
3d964ba
clarify comments around organizing information in objects
takinabradley Nov 3, 2024
0424233
Remove suggestion to show off this assignment with the community
takinabradley Nov 3, 2024
31a5022
Remove "The Principles of Object-Oriented JavaScript" as an additiona…
takinabradley Nov 3, 2024
2181fb6
Add note about modifying properties through methods vs directly
takinabradley Nov 4, 2024
9eac73b
Merge branch 'main' of github.com:TheOdinProject/curriculum into why_…
takinabradley Nov 4, 2024
0418cc3
Convey the idea of private properties without a full, concrete RPS ex…
takinabradley Nov 4, 2024
8991dcb
replace 'website' with 'app'
takinabradley Nov 4, 2024
7bb8816
Fix spelling error
takinabradley Nov 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,17 @@ If you are feeling rusty on using objects, now might be a good time to go back a

This section contains a general overview of topics that you will learn in this lesson.

- Explain how objects can be used to organize data
- Explain how objects can be used to organize functionality
- Explain what the `this` keyword is.
- How to write an object constructor and instantiate the object.
- Describe what a prototype is and how it can be used.
- Explain prototypal inheritance.
- Understand the basic do's and don't's of prototypal inheritance.
- Explain what the `this` keyword is.

### Objects as a design pattern
### Objects as a data structure

One of the simplest ways you can begin to organize your code is by grouping things into objects. Take these examples from a 'tic tac toe' game:
You've already been introduced to the basic use of a JavaScript object- storing related information with key/value pairs. This is one of the simplest ways you can begin to organize your code! Take these examples from a 'tic tac toe' game:

```javascript
// example one
Expand All @@ -59,25 +61,25 @@ const playerTwoMarker = "O";

// example two
const playerOne = {
  name: "tim",
  marker: "X"
name: "tim",
marker: "X"
};

const playerTwo = {
  name: "jenn",
  marker: "O"
name: "jenn",
marker: "O"
};
```

At first glance, the first doesn't seem so bad... and it actually takes fewer lines to write than the example using objects, but the benefits of the second approach are huge! Let me demonstrate:
At first glance, the first doesn't seem so bad.. and it actually takes fewer lines to write than the example using objects, but the benefits of the second approach are huge! Grouping related data together into objects allows you to pass the data around easily. Let me demonstrate:

```javascript
function printName(player) {
  console.log(player.name);
console.log(player.name);
}
```

This is something that you just could NOT do with the example one setup. Instead, every time you wanted to print a specific player's name, you would have to remember the correct variable name and then manually `console.log` it:
This is something that you just could NOT do with the example one setup. Instead, every time you wanted to print a specific player's name, you would have to remember the correct variable name and then manually console.log it:

```javascript
console.log(playerOneName);
Expand All @@ -88,16 +90,232 @@ Again, this isn't *that* bad... but what if you *don't know* which player's name

```javascript
function gameOver(winningPlayer){
  console.log("Congratulations!");
  console.log(winningPlayer.name + " is the winner!");
console.log("Congratulations!");
console.log(winningPlayer.name + " is the winner!");
}
```

Or, what if we aren't making a 2 player game, but something more complicated such as an online shopping site with a large inventory? In that case, using objects to keep track of each particular item's name, price, description and other things is the only way to go. You will continue to use and see objects used in this way throughout the curriculum.

### Objects as a design pattern

The grouping power of objects isn't just useful for organizing data- it's useful for organizing *functionality* as well! Using objects for this purpose is one of the core tenants of Object Oriented Programming (OOP).

The inroductory paragraph for Object Oriented Programming on Wikipedia says this:

> Object-oriented programming (OOP) is a programming paradigm based on the concept of objects, which can contain data and code: data in the form of fields (often known as attributes or properties), and code in the form of procedures (often known as methods). In OOP, computer programs are designed by making them out of objects that interact with one another.

Essentially, what this means is that code can be organized into objects that contain not only data, but also **methods** (or functions on an object) that interact with that data.

Nearly *anything* you can think about can be described as an object. To do so, all you have to do is ask yourself is "What properties (physical or conceptual) does my thing have?", and "How can I interact with it?". The properties or attributes of a *thing* are expressed as properties, and the ways you can interact with that thing are expressed as methods.

Let's take an example of some thing- we'll choose a lightbulb. A lightbulb can have a color, and it can be in either an 'on' state, or an 'off' state. These might be expressed as properties of a lightbulb object:

```javascript
const lightbulb = {
lightColor: 'fluorescent white', // this lightbulb is white,
lit: false // and is currently 'off'
}
```

You may want to have the ability to switch a lightbulb from it's unlit state to it's lit state, or vice-versa. To do that, you might add a *method*.

The easiest way to get started creating methods to interact with your objects might be combining Object Literal syntax with JavaScript's `this` keyword. The `this` keyword is used to refer to the object a particular method is called from.

The following is an example of using the `this` keyword to add two methods to our object, `switchOn`, and `switchOff`:

```javascript
const lightbulb = {
lightColor: 'fluorescent white',
lit: false,

// shorthand syntax for adding methods to objects
switchOn() {
this.lit = true
},
switchOff() {
this.lit = false
}
}

lightbulb.switchOn()
lightbulb.lit // true - we switched it on
```

These methods use the `this` keyword to refer to the object they get called from (`lightbulb`). The `this` keyword can be used to access and modify properties of an object in exactly the same way you would for any other variable that points to an object.

Feel free to copy this code in the console and experiment with it! If you're inclined, perhaps you could create a method to change the color of the light, as if it's one of those fancy RGB LEDs those gamer nerds and keyboard enthusiasts seem to like so much.

Moving past physical objects, we could also try to describe something like a game as an object. Since we've already explored Rock Paper Scissors in Foundations, let's use that as an example.

A rock paper scissors game might involve a couple basic things:

- Players' scores
- The ability to play a round (and playing a round should update a player's score)

And might also include a couple nice-to-haves

- The ability to determine the current winning player
- The ability to restart the game

So, at it's most basic, an object that represents the game might look something like this (assuming we're playing against a computer player):

```javascript
const rps = {
playerScore: 0,
computerScore: 0,
playRound(playerChoice) {
// code to play the round... (and update the scores when a player wins)
}
}
```

And if we fleshed it out, our object may come out to look something like this:

```javascript
const rps = {
playerScore: 0,
computerScore: 0,
playRound(playerChoice) {
const options = ['rock', 'paper', 'scissors']

// if an invalid choice is chosen, throw an error
if(!options.includes(playerChoice.toLowerCase())) {
throw new Error(`Expected 'rock', 'paper', or 'scissors', but got ${playerChoice}`)
}

// get the computer's choice
const computerChoice = options[Math.floor(Math.random() * 3)]


// determine the winner, apply points if necessary, and return who won
if(playerChoice.toLowerCase() === computerChoice) {
return "tie"
} else if(
(playerChoice === 'rock' && computerChoice === 'scissors') ||
(playerChoice === 'paper' && computerChoice === 'rock') ||
(playerChoice === 'scissors' && computerChoice === 'paper')
) {
this.playerScore++
return "player"
} else {
this.computerScore++
return 'computer'
}
},
getWinningPlayer() {
if(this.playerScore === this.computerScore) {
return 'tie'
} else if (this.playerScore > this.computerScore) {
return 'player'
} else {
return 'computer'
}
},
reset() {
this.playerScore = 0;
this.computerScore = 0;
}
}

rps.playRound('rock') // returns 'player' if we win...
rps.playerScore // ...and our score would have increased

// We also have the ability to check the winner and reset the game at any time
rps.getWinningPlayer() // 'player', if we won above round
rps.reset()
```

Or, what if we aren't making a 2 player game, but something more complicated such as an online shopping site with a large inventory? In that case, using objects to keep track of an item's name, price, description and other things is the only way to go. Unfortunately, in that type of situation, manually typing out the contents of our objects is not feasible either. We need a cleaner way to create our objects, which brings us to...
You may be looking at this code and thinking that you personally prefer to split your code between more functions than you see here, but also recognize that those functions may not really be a useful interaction point for anyone using your object.

But, there is no rule saying that you can't add those functions to your object as well! A common convention is to prefix methods and properties that you don't intend other people to use with an underscore (`_`). This convention conveys to others that "These things are meant to be used internally by this object, please interact with the other available methods and properties on this object's interface instead".

Let's see what that looks like!

```javascript
const rps = {
_options: ['rock', 'paper', 'scissors'],
_getRandomChoice() {
const randomIndex = Math.floor(Math.random() * 3)
return this._options[randomIndex]
},
_isTie(playerChoice, computerChoice) {return playerChoice === computerChoice},
_isPlayerWinner(playerChoice, computerChoice) {
if(
(playerChoice === 'rock' && computerChoice === 'scissors') ||
(playerChoice === 'paper' && computerChoice === 'rock') ||
(playerChoice === 'scissors' && computerChoice === 'paper')
) {
return true
} else {
return false
}
},
playerScore: 0,
computerScore: 0,
playRound(playerChoice) {
// if an invalid choice is chosen, throw an error
if(!this._options.includes(playerChoice)) {
throw new Error(`Expected 'rock', 'paper', or 'scissors', but got ${playerChoice}`)
}

// get the computer's choice
const computerChoice = this._getRandomChoice()

// determine the winner, apply points if necessary, and return who won
if(this._isTie(playerChoice, computerChoice)) {
return "tie"
} else if(this._isPlayerWinner(playerChoice, computerChoice)) {
this.playerScore++
return "player"
} else {
this.computerScore++
return 'computer'
}
},
getWinningPlayer() {
if(this.playerScore === this.computerScore) {
return 'tie'
} else if (this.playerScore > this.computerScore) {
return 'player'
} else {
return 'computer'
}
},
reset() {
this.playerScore = 0;
this.computerScore = 0;
}
}
```

Another name for these might also be **private properties**/**private methods**, and even though object literal syntax doesn't provide a way to truly make them private, you will later learn about other methods of creating objects that *can*.
takinabradley marked this conversation as resolved.
Show resolved Hide resolved

Private properties/methods aren't strictly required, but they can help make the intended use of the object more understandable, and when used thoughtfully, even protect certain properties (like the player's scores) from being modified in ways that you may not have intended. Back off, cheaters!

The methods and properties you *do* intend for others to use on your objects might be considered your object's **public interface**. Having a good, well thought out interface on your objects is important- not only because it makes your object pleasant to use by you and others, but also to keep objects flexible and extensible in the future.

This idea of grouping related functionality within an object is *extremely powerful*, and can often result in more organized, understandable code.

Furthermore, with the various object creation methods you'll learn throughout this section of the curriculum, you'll be able to easily duplicate and reuse objects like these! Imagine you have a website where users can create and play *multiple* rock-paper-scissor games at once. Managing the data and interacting with each of those games would be no sweat with objects!

<div class="lesson-note lesson-note--tip" markdown="1">

#### Objects As Machines

When you want to organize some data and functionality together in this way, but you're having trouble figuring out what kinds of properties and methods an object might contain when it's not an actual, physical item, another way you might conceptualize this idea might be to imagine the object as a little 'machine' you're making out of code that does something useful.

The properties of the machine could be thought of displays that might show information it's collected or been given to it so far, if it can currently be interacted with, what the machine has counted for a player's score... or about a billion other things, depending on what your object does.

The methods of your machine might be akin to buttons and such that make the machinde *do* a specific thing. A method might give your object new information to store in some way, turn your machine from on 'on' to 'off', allow you to input information to play a game, or switch between the turns of two different players.

Again, objects can be used to represent almost anything you can think of, the limit is your imagination! It's impossible for us to give a comprehensive list of examples.

</div>

### Object constructors

When you have a specific type of object that you need to duplicate like our player or inventory items, a better way to create them is using an object constructor, which is a function that looks like this:
Manually typing out the contents of our objects with Object Literals is not always feasible. When you have a specific type of object that you need to duplicate like our player object, inventory items, or even the entire RPS game, a better way to create them is using an object constructor, which is a function that looks like this:

```javascript
function Player(name, marker) {
Expand Down Expand Up @@ -357,7 +575,6 @@ If we had used `Object.setPrototypeOf()` in this example, then we could safely e
1. Read the article [Understanding Prototypes and Inheritance in JavaScript](https://www.digitalocean.com/community/tutorials/understanding-prototypes-and-inheritance-in-javascript) from Digital Ocean. This is a good review of prototype inheritance and constructor functions, featuring some examples.
1. To go a bit deeper into both the chain and inheritance, spend some time with [JavaScript.Info's article on Prototypal Inheritance](http://javascript.info/prototype-inheritance). As usual, doing the exercises at the end will help cement this knowledge in your mind. Don't skip them! Important note: This article makes heavy use of `__proto__` which is not generally recommended. The concepts here are what we're looking for at the moment. We will soon learn another method or two for setting the prototype.
1. You might have noticed us using the `this` keyword in object constructors and prototype methods in the examples above.

1. [Dmitri Pavlutin's article on the `this` keyword](https://dmitripavlutin.com/gentle-explanation-of-this-in-javascript/) is very comprehensive and covers how `this` changes in various situations. You should have a solid understanding of the concept after reading it. Pay special attention to the pitfalls mentioned in each section.

</div>
Expand All @@ -366,6 +583,9 @@ If we had used `Object.setPrototypeOf()` in this example, then we could safely e

The following questions are an opportunity to reflect on key topics in this lesson. If you can't answer a question, click on it to review the material, but keep in mind you are not expected to memorize or master this knowledge.

- [Explain two ways you can use objects to organize code.](#objects-as-a-data-structure)
- [What is a 'method'](#objects-as-a-design-pattern)
- [What is the `this` keyword used for?](#objects-as-a-design-pattern)
- [Write an object constructor and instantiate the object.](#object-constructors)
- [Describe what a prototype is and how it can be used.](#the-prototype)
- [Explain prototypal inheritance.](https://javascript.info/prototype-inheritance)
Expand All @@ -381,7 +601,7 @@ This section contains helpful links to related content. It isn't required, so co
- [The Principles of Object-Oriented JavaScript](https://www.amazon.com/Principles-Object-Oriented-JavaScript-Nicholas-Zakas/dp/1593275404) book by
Nicholas C. Zakas is really great to understand OOP in JavaScript, which explains concepts in-depth, which explores JavaScript's object-oriented nature, revealing the language's unique implementation of inheritance and other key characteristics, it's not free but it's very valuable.
- The first answer on this StackOverflow question regarding [defining methods via the prototype vs in the constructor](https://stackoverflow.com/questions/9772307/declaring-javascript-object-method-in-constructor-function-vs-in-prototype/9772864#9772864) helps explain when you might want to use one over the other.
- [A Beginners Guide to JavaScripts Prototype](https://medium.com/free-code-camp/a-beginners-guide-to-javascript-s-prototype-9c049fe7b34) and [JavaScript Inheritance and the Prototype Chain](https://medium.com/free-code-camp/javascript-inheritance-and-the-prototype-chain-d4298619bdae) from Tyler Mcginnis has great examples to help you understand Prototype and Prototype Chain better from the beginner's perspective.
- [A Beginner's Guide to JavaScript's Prototype](https://medium.com/free-code-camp/a-beginners-guide-to-javascript-s-prototype-9c049fe7b34) and [JavaScript Inheritance and the Prototype Chain](https://medium.com/free-code-camp/javascript-inheritance-and-the-prototype-chain-d4298619bdae) from Tyler Mcginnis has great examples to help you understand Prototype and Prototype Chain better from the beginner's perspective.
- This video from Akshay Saini is an easy way to understand the [concept of Prototype, Prototype Chain and prototypal inheritance.](https://www.youtube.com/watch?v=wstwjQ1yqWQ).
- [Interactive Scrim on objects and object constructors.](https://scrimba.com/scrim/co2624f87981575448091d5a2)
- Check out this video explanation on the [`this` keyword from DevSage](https://www.youtube.com/watch?v=cwChC4BQF0Q) that gives a different perspective on how its context changes, as well as scenarios in which `this` behaves unexpectedly.
Loading