Project: Todo List

Introduction

At this point you’ve already had a fair amount of practice using the various techniques we’ve shown you. But we’ve been throwing a lot of information your way, so before we move on we’re going to take a minute to slow down and work on one more great portfolio project.

The Todo List

Todo lists are a staple in beginning webdev tutorials because they can be very simple. There is, however, a lot of room for improvement and many features that can be added.

Before diving into the code, take a minute to think about how you are going to want to organize your project

Assignment

Follow the instructions found here, create and work on a new branch named todo-list and submit your GitHub repo’s Pull Request to the Quiz box below.


Material based on Erik Trautman | The Odin Project

Feedback

  • Is there anything we can help with up to this point? Do you have something to suggest about this chapter? Let us know in the comments below.

OOP Principles

Introduction

By this point, you will have learned and had a chance to practice the most common object-creation and organization patterns in JavaScript. But that is just the tip of the iceberg. More important than learning the syntax for factory functions or modules is figuring out how to use them effectively.

This whole series of lessons has been about the "Object Oriented Programming" paradigm (OOP). The basics of creating objects and classes are relatively straightforward. But it is not straightforward to decide what to put in each object, or when to make a new object, or when to let an object ‘inherit’ from another one.

Learning Objectives

By the end of this lesson, you should be able to do the following:

  • Explain the "Single Responsibility Principle".
  • Briefly explain the additional SOLID principles.
  • Explain what "tightly coupled" objects are and why we want to avoid them.

Luckily there are several concepts and principles that can guide us into making good decisions when it comes to our objects. This lesson is an introduction to the most important of those concepts. Keep in mind that there is not usually a very clear answer to your application design questions. Some patterns and ideas are obviously better than others, but there is often some trade-off when deciding where to put a specific function. In other words.. these principles are not rules– they’re helpful guidelines.

As you read these resources, it might help to go back to some projects you’ve already done and think about how what you’ve written measures up to the examples you see. And of course, as you move on keep these things in mind when crafting new projects.

Single Responsibility

One of the most important things to remember as you craft your objects is the Single Responsibility Principle which states that a class (or object or module.. you get the point) should only have one responsibility. Here’s a really common example. Most of our code has functions to update and write things to the DOM in addition to our application logic. It’s a really good idea to separate out your DOM stuff from the application logic.

So instead of this:

function isGameOver() {

  // game over logic goes here!

  if (gameOver){
    const gameOverDiv = document.createElement('div')
    gameOverDiv.classList.add('game-over')
    gameOverDiv.textContent = `${this.winner} won the game!`
    document.body.appendChild(gameOverDiv)
  }
}

You should extract all the DOM manipulation into it’s own module and use it like so:

function isGameOver() {

  // game over logic goes here!

  if (gameOver){
    DOMStuff.gameOver(this.winner)
  }
}

In fact – the function isGameOver shouldn’t be calling the DOM function anyway that should go elsewhere (directly in the game-loop)

The Single Responsibility Principle is the first of a commonly found set of 5 design principles called the SOLID principles. Both of the following articles mention the acronym SOLID before going on to talk about Single Responsibility. Single Responsibility is definitely the most relevant of the 5. Feel free to dig into the rest of the SOLID principles if you like.. but pay special attention to Single Responsibility.

  1. Read This Article.

  2. This article hits the same topic, and also covers the rest of ‘SOLID’ concisely.

  3. ..and one more for good measure

Loosely Coupled Objects

Obviously, all of our objects are intended to work together to form our final application. You should take care, however, to make sure that your individual objects can stand alone as much as possible. Tightly coupled objects are objects that rely so heavily on each other that removing or changing one will mean that you have to completely change another one – a real bummer.

This one is related pretty strongly to ‘Single Responsibility’ but takes a different angle. As an example, if we were writing a game and wanted to completely change how the User Interface worked, we should be able to do that without completely reworking the game logic. So we should be able to start off writing our game using primarily console.logs() and then add in a bunch of DOM functions later without touching the game logic.

  1. This article explains it pretty well.

  2. The best book we’ve ever read on this subject is Practical Object-Oriented Design In Ruby. Unfortunately, it is not free.. and not JavaScript. We feel confident in recommending it anyway. If you don’t know Ruby, it is a clear enough language that you don’t really need to learn it to follow the examples and the content of the book is sincerely fantastic.


Material based on Erik Trautman | The Odin Project

Feedback

  • Is there anything we can help with up to this point? Do you have something to suggest about this chapter? Let us know in the comments below.

Project: Restaurant Page

Introduction

Let’s use what we’ve learned and take a chance to continue practicing DOM manipulation by dynamically rendering a simple restaurant homepage! By the end, we are going to be using JavaScript alone to generate the entire contents of the website!

Assignment

  1. Start the project the same way you began the webpack tutorial project.

    1. run npm init in your project directory to generate a package.json file.

    2. run npm install webpack webpack-cli --save-dev to install webpack to the node_modules directory of your project.

      • Quick tip: the node_modules folder can get really big. It is customary to add a .gitignore file to your project so that you don’t have to sync the contents of node_modules to github. The dependencies that are stored there can be installed from your package.json by running npm install, so you don’t need to sync them.
    3. Create a src and dist directory with the following contents:

      1. an index.js file in src

      2. an index.html file in dist. Go ahead and link the main.js file in a script tag. main.js is the file that will be generated by webpack.

      3. create a webpack.config.js file that looks just like our file from the tutorial.

  2. Set up an HTML skeleton inside of dist/index.html with single <div id="content">.

  3. Inside of src/index.js write a simple console.log or alert statement and then run npx webpack. Load up dist/index.html in a browser to make sure everything is working correctly.

    • Quick tip #2: if you run npx webpack --watch you will not have to rerun webpack every time you make a change.
  4. Create a bare-bones homepage for a restaurant. Include an image, headline, and some copy about how wonderful the restaurant is. It’s okay to hard-code these into the HTML for now just to see how they look on the page.

  5. Now remove those elements from the HTML (so leave only the <html>, <body>, and <div id="content"> tags) and instead create them by using JavaScript only, e.g. by appending each new element to div#content once the page is first loaded. Since we’re all set up to write our code in multiple files, let’s write this initial page-load function inside of it’s own module and then import and call it inside of index.js.

  6. Next, set up your restaurant site to use tabbed browsing to access the Contact and Menu pages. Look at #7 on this hongkiat post for visual inspiration.

    1. Put the contents of each ‘tab’ inside of it’s own module. Each module will export a function that creates a div element, adds the appropriate content and styles to that element and then appends it to the DOM.

    2. Write the tab-switching logic inside of index.js. You should have event listeners for each tab that wipes out the current contents and then runs the correct ‘tab module’ to populate it again.

  7. If you are using GitHub pages to host your completed page you need to do a tiny bit more work to get it to show up. After running webpack the full bundled version of your site is available in the dist folder, but GH pages is looking for an index.html in the root directory of your project.

    1. Simply follow the instructions on this gist. EZPZ!
    2. Recall that the source branch for Github Pages is set in your repository’s settings.
  8. Submit the GitHub repository with the Restaurant web page in the Quiz below.


Material based on Erik Trautman | The Odin Project

Feedback

  • Is there anything we can help with up to this point? Do you have something to suggest about this chapter? Let us know in the comments below.

ES6 Modules

Introduction

Separate from the module pattern that we discussed in an earlier lesson, "modules" is a feature that arrived with ES6. Browser support for this feature is quite slim at this point, but is slowly improving and until all modern browsers support it, we can make it work using an external module bundler. ES6 modules are starting to appear in many code bases around the net and getting them up and running will give us a chance to explore some new parts of the JavaScript ecosystem, so it’s going to be a worthy excursion!

Don’t be fooled! We’re going to cover much more than just the new module syntax in this lesson! Before we can really use these modules, we’re going to have to learn about npm and webpack which are both topics that will be very useful to you even beyond this lesson. In the end, the modules themselves are simple to implement, so we’re going to take this chance to learn about a few other things.

Learning Objectives

After completing this lesson, you will be able to:

  • Explain what npm is and where it was commonly used before being adopted on the frontend.
  • Describe what npm init does and what package.json is.
  • Know how to install packages using npm.
  • Describe what a JavaScript module bundler like webpack is.
  • Explain what the concepts "entry" and "output" mean as relates to webpack.
  • Briefly explain what a development dependency is.
  • Explain what "transpiling code means" and how it relates to frontend development.
  • Briefly describe what a task runner is and how it’s used in frontend development.
  • Describe how to write an npm automation script.
  • Explain one of the main benefits of writing code in modules.
  • Explain "named exports" and "default exports".

The History of JavaScript

Why do we even need or want this stuff? What do you gain from all of this added complexity? These are good questions.. with good answers.

  • Read this article for a bit of a history lesson. It’s long, but it puts what we’re doing here in great perspective. You don’t have to code along with the examples – the tutorials we cover later will go through basically the same process. But it’s good practice and going through the same process multiple times will help it stick faster.
  • Seriously.. spend some time with that article – it really clarifies the ‘WHY’ of the rest of this lesson. [Estimated reading time: 30~45 minutes]

npm

The node package manager is a command line tool that gives you access to a gigantic repository of plugins, libraries and tools. If you have done our Fundamentals course, you will probably have encountered it when you installed the Jasmine testing framework to do our exercises.

  1. Take a couple minutes to introduce yourself to what npm is through this article.

  2. Read this article about Downloading and Installing npm packages locally. At the end of the article you’ll find the next video that teaches you how to install packages with npm:

Duration: 4 minutes

  1. This tutorial covers the package.json file, which you can use to manage your project’s dependencies

  2. If you run into trouble at any point you can check out the official docs page for more tutorials and documentation.

Yarn?

At some point, you will probably run into Yarn – a replacement for the default npm. For the most part, it does the same things though it does have a few more features. Recent versions of npm have incorporated some of the best features of Yarn, so using it won’t offer you any real advantages at this point in your career. It is a fine project, however, and may be worth your consideration in the future.

Webpack

Webpack

Webpack is simply a tool for bundling modules. There is a lot of talk across the net about how difficult and complex it is to set up and use, but at the moment our needs are few and the setup is simple enough. In fact, you can see an example of getting it up and running on the front page of their website.

Webpack is a very powerful tool, and with that power comes a decent amount of complexity – just look at the sample config file on this page 😱. Don’t let it scare you off! The basic configuration is not difficult and proficiency with webpack looks amazing on resumes.

To get us started we are going to refer to the official documentation.

  1. Code along with the first four steps of this tutorial ("Basic Setup" through "Using a Configuration")

Let’s discuss what’s going on there. After installing webpack using npm we set up a simple project that required an external library (lodash – check it out here if it’s new to you) using a simple script tag. The site lists a few reasons why this is probably not ideal and then steps through using webpack to accomplish the same thing.

There are a couple of key concepts to understanding how webpack works – entry and output. In this example, we rearranged the files into a src and dist folder. Technically we could have called those folders anything, but those names are typical. src is our source directory. In other words, src is where we write all of the code that webpack is going to bundle up for us. When webpack runs, it goes through all of our files looking for any import statements and then compiles all of the code we need to run our site into a single file inside of the dist folder (short for distribution). Our entry file, then is the main application file that links (either directly or indirectly) to all of the other modules in our project. In this example, it is /src/index.js. The output file is the compiled version – dist/main.js.

  • browse this document for more details. We’ll talk plugins and loaders in another lesson.

ES6 Modules (finally!)

Now that we (sorta) understand what webpack is doing it’s time to discuss the module syntax. There are only 2 components to it – import and export.

Of course, the import statement is the same thing that you used during the webpack tutorial! These things are simple to use.

// a file called functionOne.js
const functionOne = () => console.log('FUNCTION ONE!')

export { functionOne }
// another JS file
import { functionOne } from './functionOne'

functionOne() //this should work as expected!

There are many benefits to writing your code in modules. One of the most compelling is code reuse. If, for instance, you have written some functions that manipulate the DOM in a specific way, putting all of those into their own file as a ‘module’ means that you can copy that file and re-use it very easily!

Other benefits include all of the benefits to wrapping your code in factory functions or using the module pattern (the module pattern and ES6 modules are not the same things.. this naming convention is frustrating). By using ES6 modules you can keep different parts of your code cleanly separated, which makes writing and maintaining your code much easier and less error-prone. Keep in mind that you can definitely export constructors, classes and factory functions from your modules.

To pull it all together, let’s write a simple module and then include it in our code. We are going to continue from where the webpack tutorial left off. Before beginning your file directory should look something like this:

├── dist
│   ├── main.js
│   └── index.html
├── src
│   └── index.js
├── package-lock.json
├── package.json
└── webpack.config.js

and you should be able to bundle and run webpack by simply typing npx webpack in the terminal.

Add a new file to the src directory called myName.js with the following contents:

const myName = (name) => 'Hi! My name is ' + name;

export default myName

and then in src/index.js import and use your new function.

// import your function
import myName from './myName';

function component() {
  var element = document.createElement('div');

  // use your function!
  element.innerHTML = myName('Cody');
  return element;
}

document.body.appendChild(component());

Easy! Now, if you run npx webpack in your project directory your page should show our new function being used.

There are 2 different ways to use exports in your code: named exports and default exports. Which option you use depends on what you’re exporting. As a general rule if you want to export multiple functions use named exports with this pattern:

const functionOne = () => 'ONE'
const functionTwo = () => 'TWO'

export {
  functionOne,
  functionTwo
}

and to import them:

import {functionOne, functionTwo} from './myModule'

Using this pattern gives you the freedom to only import the functions you need in the various files of your program. So it’s perfectly fine to only import functionOne if that’s the only one you need.

The various import/export methods are best explained in the docs that we linked earlier – import and export.

Resources


Material based on Erik Trautman | The Odin Project

Feedback

  • Is there anything we can help with up to this point? Do you have something to suggest about this chapter? Let us know in the comments below.

Classes

Introduction

JavaScript does not have classes in the same sense as other Object Oriented languages like Java or Ruby. ES6, however, did introduce a syntax for object creation that uses the class keyword. It is basically a new syntax that does the exact same thing as the object constructors and prototypes we learned about in the constructor lesson.

Since we’ve already gone fairly in-depth with Constructors, you don’t have too much left to learn here beyond the new syntax. If you choose to use classes in your code (that’s fine!) you can use them much the same way as object constructors.

Learning Objectives

After this lesson and completing the assignments, you will be able to:

  • Describe the pros and cons of using classes in JavaScript.
  • Briefly discuss the difference between JavaScript’s object creation differs from a language like Java or Ruby.
  • Explain the differences between using a class to define a constructor and other prototype methods.
  • Explain what "getters" & "setters" are.
  • Understand what computed names and class fields are.
  • Describe function binding.
  • Be able to use inheritance with classes.
  • Briefly talk about the conflict in JS with functional programming and classes.

Study

  1. This article provides some pros and cons for classes. There are many people who think that class syntax is misleading for Javascript, and thus Factory Functions (from the previous lesson) are inherently better. WE are not saying that classes are bad! We just want you to be informed on the opinions of both sides.

  2. This article is probably just about all you need to start using class syntax confidently. "Getters and Setters" are a useful feature!

  3. The MDN docs are, as usual, a great resource for going a little deeper. Look especially at the ‘extends’ and ‘Mixins’ sections. React (and other frameworks) uses classes in this way. You create your components and make them extend the core React component which gives you access to all their built-in functionality.

Assignment

Go back to your "Library" example and refactor it to use class instead of plain constructors. Work on a new branch on the Exercises repository, create a new Pull Request and submit its URL to the Quiz below.

UPDATED: 27.12.2020

Feedback

  • Is there anything we can help with up to this point? Do you have something to suggest about this chapter? Let us know in the comments below.

Project: Tic-Tac-Toe

Introduction

We’re making a Tic Tac Toe game you can play in your browser!

Assignment

  1. Set up your project with a HTML, CSS and Javascript files and get the Git repo all set up.

  2. You’re going to store the gameboard as an array inside of a Gameboard object, so start there! Your players are also going to be stored in objects… and you’re probably going to want an object to control the flow of the game itself.

    1. Your main goal here is to have as little global code as possible. Try tucking everything away inside of a module or factory. Rule of thumb: if you only ever need ONE of something (gameBoard, displayController), use a module. If you need multiples of something (players!), create them with factories.
  3. Set up your HTML and write a JavaScript function that will render the contents of the gameboard array to the webpage (for now you can just manually fill in the array with "X"s and "O"s)

  4. Build the functions that allow players to add marks to a specific spot on the board, and then tie it to the DOM, letting players click on the gameboard to place their marker. Don’t forget the logic that keeps players from playing in spots that are already taken!

    1. Think carefully about where each bit of logic should reside. Each little piece of functionality should be able to fit in the game, player or gameboard objects.. but take care to put them in "logical" places. Spending a little time brainstorming here can make your life much easier later!
  5. Build the logic that checks for when the game is over! Should check for 3-in-a-row and a tie.

  6. Clean up the interface to allow players to put in their names, include a button to start/restart the game and add a display element that congratulates the winning player!

  7. Optional – If you’re feeling ambitious create an AI so that a player can play against the computer!

    1. Start by just getting the computer to make a random legal move.
    2. Once you’ve gotten that, work on making the computer smart. It is possible to create an unbeatable AI using the minimax algorithm (read about it here, some googling will help you out with this one)
    3. If you get this running definitely come show it off in the chatroom. It’s quite an accomplishment!

Submission

Create a private GitHub repository, add your instructor(s) as collaborator(s) and submit the URL in the Quiz below.


Material based on Erik Trautman | The Odin Project
LOOKING FOR HELP?

When looking for help, try doing so in the following order:

  • Did you try everything you could?
  • Did you read the documentation?
  • Did you Google for it?
  • Did you post your question on Slack/Forum?
  • Did you ask your fellow students for help?
  • Did you ask your Mentors for help?
  • Did you leave a comment on the comments section of this page?
  • Did you ask your Instructor for help?
    • Did you arrange and appointment with your instructor using Calendly? Visit this URL and set up an appointment: https://calendly.com/kostasx
    • Is it urgent? Did you try reaching him on Slack? Search for: Kostas Minaidis (kostasx)

Factory Functions and the Module Pattern

Before diving into this lesson, keep in mind that the concepts and patterns discussed within are advanced and may require that you go through the material more than once. Don’t forget to put the concepts into practice and write as many variations of the code you’ll find in the material as possible.

What’s wrong with constructors?

Object constructors are one of about a million ways to start organizing your code. They are fairly common in the wild and are a fundamental building block of the JavaScript language.

However, one of the biggest issues with constructors is that while they look just like regular functions, they do not behave like regular functions at all. If you try to use a constructor function without the new keyword, your program will not work as expected, but it won’t produce error messages that are easy to trace.

Learning Objectives

By the end of this lesson, you should be able to do the following:

  • Describe common bugs you might run into using constructors.
  • Write a factory method that returns an object.
  • Explain how scope works in JavaScript (bonus points if you can point out what ES6 changed!).
  • Explain what Closure is and how it impacts private functions & variables.
  • Describe how private functions & variables are useful.
  • Use inheritance in objects using the factory pattern.
  • Explain the module pattern.
  • Describe IIFE. What does it stand for?
  • Briefly explain namespacing and how it’s useful.

Factory function introduction

The factory function pattern is similar to constructors, but instead of using new to create an object, factory functions simply set up and return the new object when you call the function. Check out this example:

const personFactory = (name, age) => {
  const sayHello = () => console.log('hello!');
  return { name, age, sayHello };
};

const jeff = personFactory('jeff', 27);

console.log(jeff.name); // 'jeff'

jeff.sayHello(); // calls the function and logs 'hello!'

For reference, here is the same thing created using the constructor pattern:

const Person = function(name, age) {
  this.sayHello = () => console.log('hello!');
  this.name = name;
  this.age = age;
};

const jeff = new Person('jeff', 27);

Object Shorthand

A quick note about line 3 from the factory function example. In 2015, a handy new shorthand for creating objects was added into JavaScript. Without the shorthand, line 3 would have looked something like this:

return {name: name, age: age, sayHello: sayHello}

Put simply, if you are creating an object where you are referring to a variable that has the exact same name as the object property you’re creating, you can condense it like so:

return {name, age, sayHello}

With that knowledge in your pocket, check out this little hack:

const name = "Maynard"
const color = "red"
const number = 34
const food = "rice"

// logging all of these variables might be a useful thing to do,
// but doing it like this can be somewhat confusing.
console.log(name, color, number, food) // Maynard red 34 rice

// if you simply turn them into an object with brackets,
// the output is much easier to decipher:
console.log({name, color, number, food})
 // { name: 'Maynard', color: 'red', number: 34, food: 'rice' }

Scope and Closure

From simply reading the above example, you are probably already in pretty good shape to start using factory functions in your code. Before we get there though, it’s time to do a somewhat deep dive into an incredibly important concept: closure.

However, before we’re able to make sense of closure, we need to make sure you have a really good grasp on scope in JavaScript. Scope is the term that refers to where things like variables and functions can be used in your code.

In the following example, do you know what will be logged on the last line?

let a = 17;

const func = x => {
  let a = x;
};

func(99);

console.log(a); // ???????

Is it 17 or 99? Do you know why? Can you edit the code so that it prints the other value?

The answer is 17, and the reason it’s not 99 is that on line 4, the outer variable a is not redefined, rather a new a is created inside the scope of that function. In the end, figuring out scope in most contexts is not all that complicated, but it is crucial to understanding some of the more advanced concepts that are coming up soon, so take your time to understand what’s going on in the following resources.

  1. This video is simple and clear! Start here.

  2. This article starts simple and reiterates what the video covered, but goes deeper and is more specific about the appropriate terminology. At the end, he defines closure and describes the module pattern, both of which we’ll talk about more soon.

  • The previous article is great, but there is one inaccurate statement:

    All scopes in JavaScript are created with Function Scope only, they aren’t created by for or while loops or expression statements like if or switch. New functions = new scope – that’s the rule

    That statement was true in 2013 when the article was written, but ES6 has rendered it incorrect. Read this article to get the scoop!

Private Variables and Functions

Now that we’ve cemented your knowledge of scope in JavaScript, take a look at this example:

const FactoryFunction = string => {
  const capitalizeString = () => string.toUpperCase();
  const printString = () => console.log(`----${capitalizeString()}----`);
  return { printString };
};

const taco = FactoryFunction('taco');

printString(); // ERROR!!
capitalizeString(); // ERROR!!
taco.capitalizeString(); // ERROR!!
taco.printString(); // this prints "----TACO----"

Because of the concept of scope, neither of the functions created inside of FactoryFunction can be accessed outside of the function itself, which is why lines 9, 10, and 11 fail. The only way to use either of those functions is to return them in the object (see line 4), which is why we can call taco.printString() but not taco.capitalizeString(). The big deal here is that even though we can’t access the capitalizeString() function, printString() can. That is closure.

The concept of closure is the idea that functions retain their scope even if they are passed around and called outside of that scope. In this case, printString has access to everything inside of FactoryFunction, even if it gets called outside of that function.

Here’s another example:

const counterCreator = () => {
  let count = 0;
  return () => {
    console.log(count);
    count++;
  };
};

const counter = counterCreator();

counter(); // 0
counter(); // 1
counter(); // 2
counter(); // 3

In this example, counterCreator initializes a local variable (count) and then returns a function. To use that function, we have to assign it to a variable (line 9). Then, every time we run the function it console.logs count and increments it. As above, the function counter is a closure. It has access to the variable count and can both print and increment it, but there is no other way for our program to access that variable.

In the context of factory functions, closures allow us to create private variables and functions. Private functions are functions that are used in the workings of our objects that are not intended to be used elsewhere in our program. In other words, even though our objects might only do one or two things, we are free to split our functions up as much as we want (allowing for cleaner, easier to read code) and only export the functions that the rest of the program is going to use. Using this terminology with our printString example from earlier, capitalizeString is a private function and printString is public.

The concept of private functions is very useful and should be used as often as is possible! For every bit of functionality that you need for your program, there are likely to be several supporting functions that do NOT need to be used in your program as a whole. Tucking these away and making them inaccessible makes your code easier to refactor, easier to test, and easier to reason about for you and anyone else that wants to use your objects.

Back to Factory Functions

Now that we’ve got the theory out of the way, let’s return to factory functions. Factories are simply plain old JavaScript functions that return objects for us to use in our code. Using factories is a powerful way to organize and contain the code you’re writing. For example, if we’re writing any sort of game, we’re probably going to want objects to describe our players and encapsulate all of the things our players can do (functions!).

const Player = (name, level) => {
  let health = level * 2;
  const getLevel = () => level;
  const getName  = () => name;
  const die = () => {
    // uh oh
  };
  const damage = x => {
    health -= x;
    if (health <= 0) {
      die();
    }
  };
  const attack = enemy => {
    if (level < enemy.getLevel()) {
      damage(1);
      console.log(`${enemy.getName()} has damaged ${name}`);
    }
    if (level >= enemy.getLevel()) {
      enemy.damage(1);
      console.log(`${name} has damaged ${enemy.getName()}`);
    }
  };
  return {attack, damage, getLevel, getName}
};

const jimmie = Player('jim', 10);
const badGuy = Player('jeff', 5);
jimmie.attack(badGuy);

Take a minute to look through this example and see if you can figure out what’s going on.

What would happen here if we tried to call jimmie.die()? What if we tried to manipulate the health: jimmie.health -= 1000? Well, those are things that we have NOT exposed publicly so we would get an error. This is a very good thing! Setting up objects like this makes it easier for us to use them because we’ve actually put some thought into how and when we are going to want to use the information. In this case, we have jimmie’s health hiding as a private variable inside of the object which means we need to export a function if we want to manipulate it. In the long run, this will make our code much easier to reason about because all of the logic is encapsulated in an appropriate place.

Inheritance with factories

In the constructors lesson, we looked fairly deeply into the concept of prototypes and inheritance, or giving our objects access to the methods and properties of another object. There are a few easy ways to accomplish this while using factories. Check this one out:

const Person = (name) => {
  const sayName = () => console.log(`my name is ${name}`)
  return {sayName}
}

const Nerd = (name) => {
  // simply create a person and pull out the sayName function!
  const {sayName} = Person(name)
  const doSomethingNerdy = () => console.log('nerd stuff')
  return {sayName, doSomethingNerdy}
}

const jeff = Nerd('jeff')

jeff.sayName() //my name is jeff
jeff.doSomethingNerdy() // nerd stuff

This pattern is great because it allows you to pick and choose which functions you want to include in your new object. If you want to go ahead and lump ALL of another object in, you can certainly do that as well with Object.assign (read the docs for that one here).

const Nerd = (name) => {
  const prototype = Person(name)
  const doSomethingNerdy = () => console.log('nerd stuff')
  return Object.assign({}, prototype, {doSomethingNerdy})
}
  • Before moving on have a look at this article. In the second half of the article, the author goes into some things that we aren’t really talking too much about here, but you’ll be rewarded if you spend some time figuring out what he’s talking about. Good stuff!

The Module Pattern

Quick sidenote: ES6 introduced a new feature in JavaScript called ‘modules’. These are essentially a syntax for importing and exporting code between different JavaScript files. They’re very powerful and we WILL be covering them later. They are not, however, what we’re talking about here.

Modules are actually very similar to factory functions. The main difference is how they’re created.

Meet a module:

const calculator = (() => {
  const add = (a, b) => a + b;
  const sub = (a, b) => a - b;
  const mul = (a, b) => a * b;
  const div = (a, b) => a / b;
  return {
    add,
    sub,
    mul,
    div,
  };
})();

calculator.add(3,5) // 8
calculator.sub(6,2) // 4
calculator.mul(14,5534) // 77476

The concepts are exactly the same as the factory function. However, instead of creating a factory that we can use over and over again to create multiple objects, the module pattern wraps the factory in an IIFE (Immediately Invoked Function Expression).

  • Read up about IIFE’s in this article. The concept is simple: write a function, wrap it in parentheses, and then immediately call the function by adding () to the end of it.

  • An example of creating and using a module pattern: JavaScript Module Pattern Basics.

  • Additional example of creating and using a module pattern: Module pattern in JavaScript.

  • For those who prefer video lessons, here is an excellent YouTube series on modular JS that covers most of the content in this guide: Modular Javascript.

In our calculator example above, the function inside the IIFE is a simple factory function, but we can just go ahead and assign the object to the variable calculator since we aren’t going to need to be making lots of calculators, we only need one. Just like the factory example, we can have as many private functions and variables as we want, and they stay neatly organized, tucked away inside of our module, only exposing the functions we actually want to use in our program.

A useful side-effect of encapsulating the inner workings of our programs into objects is namespacing. Namespacing is a technique that is used to avoid naming collisions in our programs. For example, it’s easy to imagine scenarios where you could write multiple functions with the same name. In our calculator example, what if we had a function that added things to our HTML display, and a function that added numbers and operators to our stack as the users input them? It is conceivable that we would want to call all three of these functions add which, of course, would cause trouble in our program. If all of them were nicely encapsulated inside of an object, then we would have no trouble: calculator.add(), displayController.add(), operatorStack.add().

Additional Resources


Material based on Erik Trautman | The Odin Project
LOOKING FOR HELP?

When looking for help, try doing so in the following order:

  • Did you try everything you could?
  • Did you read the documentation?
  • Did you Google for it?
  • Did you post your question on Slack/Forum?
  • Did you ask your fellow students for help?
  • Did you ask your Mentors for help?
  • Did you leave a comment on the comments section of this page?
  • Did you ask your Instructor for help?
    • Did you arrange and appointment with your instructor using Calendly? Visit this URL and set up an appointment: https://calendly.com/kostasx
    • Is it urgent? Did you try reaching him on Slack? Search for: Kostas Minaidis (kostasx)

Project: Library

Introduction

Let’s extend the Book example from the previous lesson and turn it into a small Library app.

Assignment

  1. If you haven’t already, set up your project with skeleton HTML/CSS and JS files.

  2. All of your book objects are going to be stored in a simple array, so add a function to the script (not the constructor) that can take user’s input and store the new book objects into an array. Your code should look something like this:


let myLibrary = [];

function Book() {
     // the constructor...
}

function addBookToLibrary() {
     // do stuff here
}
  1. Hook the array up to your HTML with a render() function that loops through the array and displays each book on the page. You can display them in some sort of table, or each on their own "card". It might help for now to manually add a few books to your array so you can see the display.

  2. Add a "NEW BOOK" button that brings up a form allowing users to input the details for the new book: author, title, number of pages, whether it’s been read and anything else you might want.

  3. Add a button on each book’s display to remove the book from the library.

    1. You will need to associate your DOM elements with the actual book objects in some way. One easy solution is giving them a data-attribute that corresponds to the index of the library array.
  4. Add a button on each book’s display to change its read status.

    1. To facilitate this you will want to create the function that toggles a book’s read status on your Book prototype instance.
  5. Optional -we haven’t learned any techniques for actually storing our data anywhere, so when the user refreshes the page all of their books will disappear! If you want, you are capable of adding some persistence to this library app using one of the following techniques:

    1. localStorage (docs here) allows you to save data on the user’s computer. The downside here is that the data is ONLY accessible on the computer that it was created on. Even so, it’s pretty handy! Set up a function that saves the whole library array to localStorage every time a new book is created, and another function that looks for that array in localStorage when your app is first loaded. (make sure your app doesn’t crash if the array isn’t there!)

Read the instructions in the Exercises GitHub repository, create a new branch for this exercise, create a Pull Request and submit its URL in the Quiz below.


Material based on Erik Trautman | The Odin Project
LOOKING FOR HELP?

When looking for help, try doing so in the following order:

  • Did you try everything you could?
  • Did you read the documentation?
  • Did you Google for it?
  • Did you post your question on Slack/Forum?
  • Did you ask your fellow students for help?
  • Did you ask your Mentors for help?
  • Did you leave a comment on the comments section of this page?
  • Did you ask your Instructor for help?
    • Did you arrange and appointment with your instructor using Calendly? Visit this URL and set up an appointment: https://calendly.com/kostasx
    • Is it urgent? Did you try reaching him on Slack? Search for: Kostas Minaidis (kostasx)

UPDATED: 27.12.2020

Objects and Object Constructors

Introduction

In our JavaScript fundamentals course, you should have learned the basics of using objects to store and retrieve data. Let’s start with a little refresher.

There are multiple ways to define objects but in most cases, it is best to use the object literal syntax as follows:

const myObject = {
  property: 'Value!',
  otherProperty: 77,
  "obnoxious property": function() {
    // do stuff!
 }
}

There are also 2 ways to get information out of an object: dot notation and bracket notation.

// dot notation
myObject.property // 'Value!'

// bracket notation
myObject["obnoxious property"] // [Function]

Which method you use will depend on context. Dot notation is cleaner and is usually preferred, but there are plenty of circumstances when it is not possible to use it. For example, myObject."obnoxious property" won’t work because that property is a string with a space in it. Likewise, you can not use variables in dot notation:

const variable = 'property'

myObject.variable // this gives us 'undefined' because it's looking for a property named 'variable' in our object

myObject[variable] // this is equivalent to myObject['property'] and returns 'Value!'

If you are feeling rusty on using objects, now might be a good time to go back and review the content in Fundamentals 5 from our JavaScript 101 course.

Learning Outcomes

By the end of this lesson, you should be able to do the following:

  • 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 prototypical inheritance.
  • Explain what Object.create does.

Objects as a Design Pattern

One of the simplest ways you can begin to organize your code is by simply grouping things into objects. Take these examples from a ‘tic tac toe’ game:

// example one
const playerOneName = "tim"
const playerTwoName = "jenn"
const playerOneMarker = "X"
const playerTwoMarker = "O"

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

const playerTwo = {
  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 are huge! Let me demonstrate:

function printName(player) {
  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:

console.log(playerOneName)
console.log(playerTwoName)

Again, this isn’t that bad… but what if you don’t know which player’s name you want to print?

function gameOver(winningPlayer){
  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 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…

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:

function Player(name, marker) {
  this.name = name
  this.marker = marker
}

and which you use by calling the function with the keyword new.

const player = new Player('steve', 'X')
console.log(player.name) // 'steve'

Just like with objects created using the Object Literal method you can add functions to the object:

function Player(name, marker) {
  this.name = name
  this.marker = marker
  this.sayName = function() {
    console.log(name)
  }
}

const player1 = new Player('steve', 'X');
const player2 = new Player('also steve', 'O');
player1.sayName(); // logs 'steve'
player2.sayName(); // logs 'also steve'

Exercise

Write a constructor for making "book" objects. We will revisit this in the project at the end of this lesson. Your book objects should have the book’s title, author, the number of pages, and whether or not you have read the book

Put a function into the constructor that can report the book info like so

book.info() // "The Hobbit by J.R.R. Tolkien, 295 pages, not read yet"

note: it is almost always best to return things rather than putting console.log() directly into the function. In this case, return the info string and log it after the function has been called:

console.log(theHobbit.info());

Use the Exercises GitHub repository for the exercises of this lesson. You will have to create a new branch named js-object-constructors, create a Pull Request and submit its URL in the Quiz at the bottom of this page.

The Prototype

Before we go much further, there’s something important you need to understand about JavaScript objects. All objects in JavaScript have a prototype. Stated simply, the prototype is another object that the original object inherits from, which is to say, the original object has access to all of its prototype’s methods and properties.

This concept is an important one, so you’ve got some reading to do. Make sure you really get this before moving on!

  1. This article is a straightforward introduction and demonstration of the concept. It also covers constructors again.. good time for a review! The important bits here, once you’ve covered the basics are ‘Prototype-based inheritance’ and the ‘Prototype chain’

  2. Watch this 8-minute quick introduction to the Prototype by Net Ninja:

  1. To go a bit deeper into both the chain and inheritance spend some time with this great article. 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.

If you’ve understood the concept of the prototype then this next bit about constructors will not be confusing at all!

function Student(name, grade) {
  this.name = name
  this.grade = grade
}

Student.prototype.sayName = function() {
  console.log(this.name)
}
Student.prototype.goToProm = function() {
  // eh.. go to prom?
}

If you’re using constructors to make your objects it is best to define functions on the prototype of that object. Doing so means that a single instance of each function will be shared between all of the Student objects. If we declare the function directly in the constructor like we did when they were first introduced that function would be duplicated every time a new Student is created. In this example, that wouldn’t really matter much, but in a project that is creating thousands of objects, it really can make a difference.

Recommended Method for Prototypal Inheritance

So far you have seen several ways of making an object inherit the prototype from another object. At this point in history, the recommended way of setting the prototype of an object is Object.create ( here is the documentation for that method.) Object.create very simply returns a new object with the specified prototype and any additional properties you want to add. For our purposes you use it like so:

function Student() {
}

Student.prototype.sayName = function() {
  console.log(this.name)
}

function EighthGrader(name) {
  this.name = name
  this.grade = 8
}

EighthGrader.prototype = Object.create(Student.prototype)

const carl = new EighthGrader("carl")
carl.sayName() // console.logs "carl"
carl.grade // 8

You can probably figure out what’s going on here. After creating the constructor for EighthGrader we set it’s prototype to a new object that has a copy of Student.prototype.

A warning… this doesn’t work:

EighthGrader.prototype = Student.prototype

because it will literally set EighthGrader’s prototype to Student.prototype (i.e. not a copy), which could cause problems if you want to edit something in the future. Consider one more example:

function Student() {
}

Student.prototype.sayName = function() {
  console.log(this.name)
}

function EighthGrader(name) {
  this.name = name
  this.grade = 8
}

// don't do this!!!
EighthGrader.prototype = Student.prototype

function NinthGrader(name) {
  this.name = name
  this.grade = 9
}

// noooo! not again!
NinthGrader.prototype = Student.prototype

NinthGrader.prototype.sayName = function() {console.log("HAHAHAHAHAHA")}

const carl = new EighthGrader("carl")
carl.sayName() //uh oh! this logs "HAHAHAHAHAHA" because we edited the sayName function!

If we had used Object.create in this example then we could safely edit the NinthGrader.prototype.sayName function without changing the function for EighthGrader as well.

Additional Resources

Try using these resources if you want another perspective to understand the concept.

  • This article from Lydia Hallie and this next video from Avelx explains the Prototype concept with graphics and simple language:

Student Approved Resource

Assigment: Web Banking

Implement the following functionality in JavaScript:

    1. Create a Function constructor that creates Bank Accounts
    1. Implement the following prototype methods:
  • 2.1. deposit: will deposit an amount to the current balance
  • 2.2. withdraw: will withdraw an amount from the current balance an return the withdrawn amount
    • Validation rules include:
    • 2.2.1. Amount must not be negative number
    • 2.2.2. Amount must be of type Number
    • 2.2.3. Amount must not exceed current balance
  • 2.3. getBalance: will return the current balance
    1. Automatically give a new IBAN number to new accounts. (Static property)

IMPLEMENTATION EXAMPLE:

const newAccount = new Account( "Kostas Minaidis" );    
// New account created for: Kostas Minaidis
// IBAN: GR00010003

newAccount.getBalance()     // 0
newAccount.deposit( 100 )  
newAccount.getBalance()     // 100
newAccount.withdraw( 50 )  
newAccount.getBalance()     // 50

newAccount.withdraw( 500 )   // Error 'Insufficient balance!'
newAccount.withdraw( "50" )  // Error 'Invalid amount'
newAccount.withdraw( -150 )  // Error 'Invalid amount'

Use the Exercises GitHub repository for the exercises of this lesson. You will have to create a new branch named js-object-constructors, create a Pull Request and submit its URL in the Quiz below.


Material based on Erik Trautman | The Odin Project
LOOKING FOR HELP?

When looking for help, try doing so in the following order:

  • Did you try everything you could?
  • Did you read the documentation?
  • Did you Google for it?
  • Did you post your question on Slack/Forum?
  • Did you ask your fellow students for help?
  • Did you ask your Mentors for help?
  • Did you leave a comment on the comments section of this page?
  • Did you ask your Instructor for help?
    • Did you arrange and appointment with your instructor using Calendly? Visit this URL and set up an appointment: https://calendly.com/kostasx
    • Is it urgent? Did you try reaching him on Slack? Search for: Kostas Minaidis (kostasx)

UPDATED: 26.02.2021

CONTRIBUTORS:

Introduction

Organizing your JavaScript code

One of the most daunting parts of JavaScript is learning how to organize your code. The reason this subject can be so overwhelming is not because JavaScript is so much more complex than other languages, but because it is incredibly forgiving! Many languages force you into using specific patterns and data structures in your code but that is not true in JavaScript.

In the beginning, this is a great thing! For example, if you just want to make a simple button on your webpage do something you can set that up in a couple lines of code. However, as your program becomes more complex, it can become hard to maintain unless you take care to organize your code and because JavaScript is such a flexible language how you do that is entirely up to you. For many coders making decisions about design patterns is crippling so we’re here to help.

This lesson series is going to cover a few of the most common design patterns that occur in modern JavaScript code, we will discuss some pros and cons of each pattern and will give you a chance to practice using each pattern in a project.

The patterns we’ll be covering in this series are:

  • Plain Old JavaScript Objects and Object Constructors
  • Factory Functions and the Module Pattern
  • Classes
  • ES6 Modules

Going through these will give us a chance to learn about a few other important concepts in JavaScript such as "closure", "prototypes", "IIFEs" and more! This series covers the most important parts of JavaScript after simply learning the basics of the language… are you ready?

Resources


Material based on Erik Trautman | The Odin Project
LOOKING FOR HELP?

When looking for help, try doing so in the following order:

  • Did you try everything you could?
  • Did you read the documentation?
  • Did you Google for it?
  • Did you post your question on Slack/Forum?
  • Did you ask your fellow students for help?
  • Did you ask your Mentors for help?
  • Did you leave a comment on the comments section of this page?
  • Did you ask your Instructor for help?
    • Did you arrange and appointment with your instructor using Calendly? Visit this URL and set up an appointment: https://calendly.com/kostasx
    • Is it urgent? Did you try reaching him on Slack? Search for: Kostas Minaidis (kostasx)