Refers to where can we use variables
let
, const
, and function argumentsconst width = 100;
const height = 100;
const drawFoo = (r) => {
const x = Math.floor(Math.random() * width);
const y = Math.floor(Math.random() * height);
for (let i = 0; i < 10; i++) {
drawCircle(x + i, y + i, r);
}
}
Variables defined at the top level of the file are in global scope. In this code, width
, height
, and drawFoo
.
Function arguments and variables defined at the top level of the function are in the scope defined by the function. In this code, r
, x
, and y
.
A for
loop creates a new scope for its loop variable that covers the body of the loop.
At any point in the code we can only refer to variables defined in the scopes that enclose that place in the code.
const foo = (c1, c2) => {
if (c2) {
let i = 10;
if (c2) {
let i = 20;
{ // this block just introduces a new scope
let i = 30;
console.log(i);
}
console.log(i);
}
console.log(i);
}
}
Each let i
creates a new variable in the smallest scope containing it which “shadows” any i
variables from enclosing scopes.
» foo(true, true)
30
20
10
const bar = (c1, c2) => {
if (c2) {
let i = 10;
if (c2) {
i = 20;
{
i = 30;
console.log(i);
}
console.log(i);
}
console.log(i);
}
}
Same scopes but assigning new values to i
variable from the outer scope rather than creating new variables.
» bar(true, true)
30
30
30
const mysteryOne = (a, b) => {
return a + b * 2;
}
What does this function call evaluate to?
mysteryOne(10, 3)
16. Not very mysterious.
Everything we need to understand about this function is defined in the scope of the function.
const mysteryTwo = (a) => {
return a + b * 2;
}
What does this function call evaluate to?
mysteryTwo(10)
Dunno. We can’t understand this function in isolation. We need to see how b
is defined and where it changes.
I.e. we need to look outside the scope of the function to understand it.
Suppose we look in the global scope and find this:
const b = 42;
Maybe b
isn’t the best name but now we now know everything we need to know to understand the behavior of mystery2
.
Suppose we look in the global scope and find this:
let b = 42;
Oh no.
Everything is still pretty much a mystery. We have to look at all the code in our program to see when b
changes in order to fully understand mystery2
.
Keep functions short (~5 lines is good)
Prefer taking arguments over referencing global variables
Prefer returning values rather than setting global variables
Functions that do need to make changes to global variables should be higher-level functions.
let score = 0;
const updateScore = (obstacles) => {
score += obstacles * 10;
score += bonusPoints(obstacles);
}
const bonusPoints = (obstacles) => {
let bonus = 0;
// some complicated computation using obstacles
return bonus;
}
Because updateScore
calls bonusPoints
, it is a higher-level function.
let score = 0;
const updateScore = (obstacles) => {
score += obstacles * 10;
updateBonusPoints(obstacles);
}
const updateBonusPoints = (obstacles) => {
let bonus = 0;
// some complicated computation using obstacles
score += bonus;
}
The updateBonusPoints
function is less useful than bonusPoints
from the previous slide. And it also makes updateScore
harder to read.