This is the curriculum for the 2018 Foxtrot Web Developer Bootcamp.

Javascript Scope Basics from LEARN on Vimeo

JavaScript Scope

Now that you have a good grasp on some JavaScript basics, we're going to introduce a term that will help explain some of the behaviour you might have seen before in your looping and functional exercises. The term is "Scope". If you haven't heard the word before, that's ok. It's programmer speak for "where an item, be it a variable, function, object, or anything else in your program, can be seen". If you look up scope on your own you'll come across some very in depth discussions on different types of scope. The ones we're going to focus on right now are global scope, local scope, and lexical scope. Open up your a JavaScript console and follow along.

var name = "Tom";

The variable 'name' is a good example of Global Scope. The variable 'name' here is not inside any function or object, in fact the only thing containing the variable is the JavaScript Console.This simple fact gives 'name' a Global Scope and anything else that we put inside the console will be able to see it. Let's give it a try

var nameCaller = function(){
  console.log(name);
}
nameCaller();

Here is a function assigned to the variable nameCaller that when called will output the variable name to the console. After assigning the function we're going to immediately call it.

As you can see, even though the console.log command is inside of the function, it still has access to the variable 'name' because of its global scope. You can even change the value assigned to the global variable inside of a function, as such...

var nameChanger = function(){
  name = "Jerry";
}
nameChanger();
console.log(name);

Here's another simple function that will change the global variable 'name'. As before, I'm going to immediately call the function and then I'm going to see what name is after the function has finished.

As you can see our name is no longer "Tom". Even though the 'name' variable was initially stated outside of the function, the function can still do things with the variable because of its global scope.

The next level of scope is called local scope, or sometimes functional scope. This is the scope inside of a function and only exists locally when you are working within that function. Here's a representation of that visually.

// Global Scope A
var myFunction = function () {
  // Local Scope B
  var myOtherFunction = function () {
    // Local Scope C
  };
  // Local Scope B
};

Scope A is outside of any object or function, just like our initial variable 'name' and it therefore Global a Scope. Scopes B and C are both examples of local scope. Scope B exists anywhere inside of myFunction, but Local Scope C exists only to things happening inside of myOtherFunction. Here's an example of that in action.

var nameChanger = function(){
  name = "Tom";
  var name2 = "Jerry";
}
nameChanger();
console.log(name);
console.log(name2);

Here we have another example of the nameChanger variable, which is now a function changing name back to 'Tom' because it is currently "Jerry" and giving Jerry its own variable 'name2'. Then we're going to immediately call nameChanger and log in our console both name and name2. As you can see, the command to log the variable 'name', properly displayed "Tom" because we changed it back with our function, but when we tried to log the 'name2' variable we were given the error 'name2 is not defined'. Containing the name2 variable completely inside of the nameChanger function gave it a local scope inside that function and the variable effectively disappears after the function is complete.

One thing that is important to know when working with JavaScript is that if we had only stated name2 = "Jerry"; instead of var name2 = Jerry, it would have been instantiated as a global variable instead of a local variable. This is VERY BAD programming and can cause major issues in many programs when the global variables you have defined clash with other variables that your program might need access to from other sources. Leaving off the var descriptor on a variable is something that you should never ever EVER do.

The last type of scope that we will cover is called Lexical Scope. In short, Lexical Scope is when you contain a function completely inside of another function and in JavaScript is called 'closure'. Closures and Lexical Scope will be covered in detail in the next video.

However, before you go watch that video, I want to tie the discussion of Scope into the reading you did last night on the topic of 'this'. 'this' is a key word in JavaScript and is a very versatile(, and sometimes confusing,) tool. With permission, I'm going to use someone else's words to explain 'this' and Scope. Todd Motto, a developer at Google, put out an article which, in part, covered this very subject. A link to the whole article is in the text below.

Each scope binds a different value of this depending on how the function is invoked. We've all used the this keyword, but not all of us understand it and how it differs when invoked. By default this refers to the outer most global object, the window. We can easily show how invoking functions in different ways binds the this value differently:

var myFunction = function () {
  console.log(this); // this = global, [object Window]
};
myFunction();

In this first chunk of code 'this' is logged, but is not logged off of anything in particular and is therefore global and refers to the Window object.

var myObject = {};
myObject.myMethod = function () {
  console.log(this); // this = Object { myObject }
};

When referencing 'this' from inside an object the key word refers to the Object from which it was called.

var nav = document.querySelector('.nav'); // <nav class="nav">
var toggleNav = function () {
  console.log(this); // this = <nav> element
};
nav.addEventListener('click', toggleNav, false);

Here the code calls a toggleNav function which assigns the value of this to the

Objects through Closures

Object with Data

Creating an object in JavaScript is easy:

var person = { name: "Alex Keaton", phone: 123456789 };

Then we can access the properties with the "dot" notation:

person.name;    -> "Alex Keaton"
person.phone;   -> 123456789

Object with Function/Method

Objects can also contain functions which are then called methods:

var person = {
  name: "Alex Keaton",
  phone: 123456789,
  getData: function() { return this.name+"-"+this.phone }
};

person.getData();   -> "Alex Keaton-123456789"

Creating New Objects

Let's make a function to create new objects, called a constructor or factory:

function createNewPerson(newName, newPhone) {  // begin createNewPerson
  return {                        // begin object
    name: newName,
    phone: newPhone,
    getData: function() {         // begin function
      return this.name+"-"+this.phone
    }                             // end function
  };                              // end object
}                                 // end createNewPerson

So now we can make objects easily:

var person = createNewPerson("Joe", 123);
person.name;
person.phone;
person.getData();

Objects are independent of each other:

var person2 = createNewPerson("Bill", 987);
person2.name;
person2.phone;
person2.getData();

However, object variables are references:

person.name;    -> "Joe"
person = person2;
person2.name = "William";
person2.name;   -> "William"
person.name;    -> "William"     // name changed without us doing anything...

You can see this animated if you go to http://pythontutor.com, select javaScript, and paste in the code.
For further in-depth information see Javascript Enlightenment

Private Data

We can use local variables to create private inaccessible data as part of closures:

function createNewCounter() {
  var value = 17;
  return {
    getValue: function() { return value; }
  }
}

var counter = createNewCounter();
value;                -> undefined // the local variable value is inaccessible
counter.value;        -> undefined // value is not part of the object
counter.getValue();   -> 17        // the getValue function can access the local variable

We can access the local variable value from inside the object but not from the outside.
Notice that this is not needed to access value (unlike accessing object properties, see createNewPerson).

Let's add another method:

function createNewCounter() {
  var value = 0;
  return {
    getValue: function() { return value; },
    increase: function() { value++; }
  }
}

And use it to count:

counter = createNewCounter();
counter.getValue();   -> 0
counter.increase();
counter.getValue();   -> 1

We can also count down:

function createNewCounter() {
  var value = 0;
  return {
    getValue: function() { return value; },
    increase: function() { value++; },
    decrease: function() { value--; }
  }
}
counter = createNewCounter();
counter.getValue();   -> 0
counter.increase();
counter.getValue();   -> 1
counter.decrease();
counter.getValue();   -> 0

And the objects are independent, just like before:

var counter2 = createNewCounter();
counter2.getValue();  -> 0
counter2.increase();
counter2.increase();
counter2.getValue();  -> 2

counter.getValue();   -> 0

Resources

For more information on objects see:
Javascript Enlightenment
You Don't Know JS: Up & Going - Chapter 2: Into JavaScript
MDN: Objects

For more information on closures see:
Javascript Enlightenment, chapter 7.
You Don't Know JS: Function vs. Block Scope
You Don't Know JS: Scope Closure
(Caution: not for the faint of heart)

Writing Better Code

Especially when you are getting started, it can be hard to know what is good code and what isn't. But where can you learn these good habits?

Linters are a good way to learn to code better. A linter reads through the code you write and highlights the bits that could be better, or that aren't up to par. If you pay attention to the fixes they suggest, you'll find yourself picking up good habits over time.

Linter Options

  1. You can copy and paste your code into a linter in your browser like this one JSHint

  2. It can be hard to remember the extra step of copy and pasting your code into a web page. Luckliy though, our text editor Atom has linter packages that you can download, so that the linter suggestions show up immediately as you write your code

To install our JS Linter in Atom:

  • Open Atom and find the "Preferences" option in the main drop down to open settings
  • Find the "Install" section in settings
  • In the search bar, look for "linter-jshint"
  • Choose "Install" in the linter-jshint result box
  • Try creating a new .js file and typing some javascript!

Car Object Challenge

Story 1

Create a function that creates car objects which have a make, model year, and color.

Add a function that returns make, model year, and color as one string and use the method to tell the user the car's information.

Challenges:

  • Write a function that creates an object that represents a car with the following properties:
    • model year
    • make
    • color
  • Add a function to the object that is being returned that concatenates the make, year and color.

Story 2

The car can accelerate, brake, and tell you its speed.

Challenges:

  • Add a speed variable to the closure of the car object. Add the following functions to the object:
    • getSpeed: returns current speed
    • accelerate: increases the speed by 10mph (but does not return anything)
    • brake: decreases the speed by 7mph (but does not return anything)

Story 3

Create a car object and use a while loop to take its speed up to 50mph.
Then use a while loop to brake down to 0mph.
Surprise: it doesnt stop at 0mph, fix that.

Challenges:

  • Create a loop that accelerates the car up to 70mph.
  • Create a loop that decelerates the car to 0mph.
  • Call break after the car is at 0mph.
  • Fix the issue.

Hint: The loops use a car object, but is not part of the car object.

Story 4

Challenge:

  • Limit the car's maximum speed to 85mph. Try taking it above 80mph and see what happens.

Hint: What should happen when you call accelerate at 80mph?

Story 5 (Extra)

Challenge:

  • Sometimes roads are slippery and downhill, and sometimes brakes fail: make the brake change the speed by a random amount with a maximum of minus 1/2 of the current speed. (Hint: Math.random()). How many iterations does it take to stop the car?

Resources


Objects explained

Password Checker Challenge

Goal

You are writing the user registration page for a secure web site.
On the registration page, the user has to enter a user ID and a password, which has to adhere to the to following criteria:

  • User ID and password cannot be the same
  • User ID and password have to be at least six characters long
  • User ID cannot contain the following characters: !#$
  • Password has to contain at least one of: !#$
  • Password cannot be "password"

Implement functions to perform the checks.
Then:

Write a main method that

  • First lets a user input both user ID and password,
  • Then create methods corresponding to criteria above to evaluate the user ID and password
  • Then output whether the combination the combination is acceptable or not.
  • Run the program and test it for all criteria listed above by inputting different values.
  • Hint: See how the javascript String class can help you.

Stretch Goal

  • Password has to contain at least one digit

Super Stretch Goal

  • Password has to contain a lower and an uppercase letter
    • Hint: Cleverly use toUpperCase or toLowerCase
    • Be sure to test with a password that have no letters

Object Oriented Password Checker

Take your Password Checker and write in code that will notify the user when they have entered a non-valid user name and password.
Tasks:

  • For each criteria create a function that checks the string for the password or username and returns one of two objects.

    • Either { valid: true } or { valid: false, reason: "User ID cannot contain $"} with the reason for the rule failing.
  • Then create a main function that runs all functions and prints out all failures for all criteria one at a time.

Today's Tentative Schedule


9:15am - Stand Up


9:30am - More Javascript: Arrays, Loops and Iteration followed by challenges


11:30am - Challenge: Magic 8 Ball


12:00 noon - Lunch


1pm - Continue challenges


4.30pm - Review


5pm - Class Ends