Express ES6 - Solutions to JS Scope

Context

ES6 gives us more tools to be explicit about variables and control scope.

Learning Objectives

  • know when to use let
  • know when to use const
  • know when to use var

ES6 Variable Declaration: Clean Up Sloppy Code Practices

  • declare variables in the right place and time
  • values of variables don't bleed over into the wrong place
  • var declaration still works with looks out but not in
  • const and let do not
  • use these new tools to be more explicit about what your variables are and where they are being used.

Block level scoping

Q. What is a block?

A. Anything between curly braces.

while(){
  // yes
}

for(...){
  //yes
}

if(){
  //yes
}

switch(){
  case: //no
  case: //no
}
switch(){
  case: foo{
    //yes
  }
  case: bar{
    //yes
  }
}

What is Let and Const?


  • LET: allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used.
  • CONST: they are not immutable, but the reference to the variable cannot be changed. also allows you to declare the variable within that block scope.

E.g. const cannot be reassigned

var hello = 2;
const bye = 10;
for (var i = 0; i < hello; i++) {

  // because of block level scope, this creates a new
  // const, and hence does not come in conflict with the const bye globally

  const bye = 5;
  console.log(bye);
}
console.log(bye);

E.g. let - only exist in the {} scope

for (var i = 1; i <= 5; i++){
  setTimeout(function () {
    console.log(i);
  }, 1000)
}

for (let i = 1; i <= 5; i++){
  setTimeout(function () {
    console.log(i);
  }, 1000)
}

For let / const, you can only declare a variable inside of its scope once. JavaScript

const key = 'abc123';
let points = 50;
let winner = false;
let points = 100;

-> The browser says points has already been declared.


Now, what if I had this?

JavaScript

const key = 'abc123';
let points = 50;
let winner = false;

if(points > 40) {
   let winner = true
}

The important thing here is that these two winner variables are actually two separate variables. They have the same name, but they are both scoped differently:

let winner = false outside of the if loop is scoped to the window. let winner = true inside the if loop is scoped to the block.


When to use let and const

We are switching to let and const in nodejs.

Don't use var unless you have a specific (scope) reason. If you want a global variable, just declare it outside of anything.

The general rules are:

  • let for basic type variables: strings, numbers, booleans, etc.
  • const for objects and arrays.
  • const for basic type variables whose value you don't want to change over the course of your program.
  • Ex.: const milesPerKilometer = 1.6;

Arrow Functions

ES6 anaonymous functions that have their own scope

Arrow function is a more concise syntax for writing function expressions. They utilize a new token, "=>", that looks like a fat arrow. Arrow functions are anonymous and change the way scope is calculated in JS.


How do we use it?

// ES5
var multiply = function(x, y) {
  return x * y
};

// Longest syntax:

// Replace the `function` keyword with `=>`, put it on the other side.
// ES6
var multiply = (x, y) => {
  return x * y
};

// Single Line Syntax:
var multiply = (x, y) => { return x * y };

// Concise Syntax: ( only if you have a single parameter )
var multiply = x => { return x * 3 };

// Implicit Return Syntax:
var multiply = x => { x * 3 };

// Implicit Return Syntax w/o parentheses:
var multiply = x => x * 3;

// Implicit Return Syntax w/o curly braces, zero parameters:
var multiply = () => 5 * 3;

// anonymous functions
setTimeout( function(){
  console.log("hello");
}, 1000 );

setTimeout( () => { console.log("hello"); }, 1000 );
setTimeout( () => console.log("hello"), 1000 );

Review: our JS scope problems in the browser:


Basic block scope

Now, Javascript looks out if you want it to, but not in.

Still basic block scope + async timing

People commonly make this error:

for (var i=0; i<5; i++) {

  var link = document.createElement("a");

  link.innerHTML = "Link " + i;

  link.addEventListener('click', function() {
    alert(i);
  });

  document.body.appendChild(link);
}


// or a while loop if we want to be specific about the exact scope context:
var i = 0;

while( i < 5 ){

  var link = document.createElement("a");

  link.innerHTML = "Link " + i;

  link.addEventListener('click', function() {
    alert(i);
  });

  document.body.appendChild(link);

  i++;
}

The value of i is not held inside the event listener function.


solutions


Use let

for (let i=0; i<5; i++) {

  var link = document.createElement("a");

  link.innerHTML = "Link " + i;

  link.addEventListener('click', function() {
    alert(i);
  });

  document.body.appendChild(link);
}

// while example
var i = 0;

while( i < 5 ){

  let j = i;

  var link = document.createElement("a");

  link.innerHTML = "Link " + j;

  link.addEventListener('click', function() {
    alert(j);
  });

  document.body.appendChild(link);

  i++;
}

Let / Const Pairing Exercise

  • create a new index.js file
  • copy and paste all of the code into the file
  • without erasing an entire line get rid of the syntax errors by editing that line
  • console.log each variable value

let monkey = 6;
if( true == true ){
  console.log( "monkey is:"+monkey );
}
// NOTE: Constants can be declared with uppercase or lowercase, but a common
// convention is to use all-uppercase letters.

// define MY_FAV as a constant and give it the value 7
const MY_FAV = 7;

// this will throw an error - Uncaught TypeError: Assignment to constant variable.
MY_FAV = 20;

// MY_FAV is 7

// trying to redeclare a constant throws an error -  Uncaught SyntaxError: Identifier 'MY_FAV' has already been declared
const MY_FAV = 20;

// the name MY_FAV is reserved for constant above, so this will fail too
var MY_FAV = 20;

// this throws an error too
let MY_FAV = 20;

// it's important to note the nature of block scoping
if (MY_FAV === 7) {
    // this is fine and creates a block scoped MY_FAV variable
    // (works equally well with let to declare a block scoped non const variable)
    let MY_FAV = 20;

    // MY_FAV is now 20

    // this gets hoisted into the global context and throws an error
    var MY_FAV = 20;
}

// MY_FAV is still 7

// throws an error - Uncaught SyntaxError: Missing initializer in const declaration
const FOO;

// const also works on objects
const MY_OBJECT = {'key': 'value'};

// Attempting to overwrite the object throws an error - Uncaught TypeError: Assignment to constant variable.
MY_OBJECT = {'OTHER_KEY': 'value'};

// However, object keys are not protected,
// so the following statement is executed without problem
MY_OBJECT.key = 'otherValue';

// The same applies to arrays
const MY_ARRAY = [];
// It's possible to push items into the array
MY_ARRAY.push('A'); // ["A"]
// However, assigning a new array to the variable throws an error - Uncaught TypeError: Assignment to constant variable.
MY_ARRAY = ['B'];

// change this to hold the value of i
for (var i = 1; i <= 5; i++){
  setTimeout(function () {
    console.log(i);
  }, 1000)
}

Arrow Function Pairing Exercise

  • use the same index.js file as above
  • copy and paste all of the code into the file
  • execute all the functions and console.log each value
  • do not write the console.log in the function. Capture the output in a variable and console.log that.
// ES5
var multiply = function(x, y) {
  return x * y
};

// Longest syntax:

// Replace the `function` keyword with `=>`, put it on the other side.
// ES6
var multiply = (x, y) => {
  return x * y
};

// Single Line Syntax:
var multiply = (x, y) => { return x * y };

// Concise Syntax: ( only if you have a single parameter )
var multiply = x => { return x * 3 };

// Implicit Return Syntax w/o parentheses:
var multiply = x => x * 3;

// Implicit Return Syntax w/o curly braces, zero parameters:
var multiply = () => 5 * 3;

// anonymous functions
setTimeout( function(){
  console.log("hello");
}, 1000 );

setTimeout( () => { console.log("hello"); }, 1000 );
setTimeout( () => console.log("hello"), 1000 );

Further

Replace the ES5 syntax for the iterators in these examples: https://wdi-sg.github.io/gitbook-2018/02-js/js-callbacks-iterators/readme.html use them with single and also 2 input parameters. (index and keys as the second parameters)

results matching ""

    No results matching ""