Week 7
Pass by
Value vs Reference
Pass by Value
Primitive data types
- number
- string
- boolean
- undefined
- null
let lunch = "Leftovers";
let dinner = lunch;
console.log(lunch); // Leftovers
console.log(dinner); // Leftovers
lunch = "Sandwich";
console.log(lunch); // Sandwich
console.log(dinner); // Leftovers
Creates a copy
Computer Memory
Leftovers
Leftovers
lunch
dinner
Pass by Reference
Points to value in memory
Complex data types
- objects
- arrays
- functions
let movie = { title: "Frozen" };
let newMovie = movie;
console.log(movie);
// {title: "Frozen"}
console.log(newMovie);
// {title: "Frozen"}
movie.title = "Tarzan";
console.log(movie);
// {title: "Tarzan"}
console.log(newMovie);
// {title: "Tarzan"}let cats = ["Felix", "Kitty"];
let newCats = cats;
newCats.push("Mittens");
console.log(cats);
// ["Felix", "Kitty", "Mittens"]
console.log(newCats);
// ["Felix", "Kitty", "Mittens"]
Computer Memory
{ "title": "frozen" }
movie
newMovie
const cats = ["Felix", "Kitty"];
cats.push("Mittens");
console.log(cats);
// What will happen here?const dog = { name: "Doug" };
dog.breed = "Labrador Retriever";
console.log(dog);
// What will happen here?
Since objects and arrays are passed by reference, even objects and array declared with const can be modified.
const cats = ["Felix", "Kitty"];
cats.push("Mittens");
console.log(cats);
// ["Felix", "Kitty", "Mittens"]const dog = { name: "Doug" };
dog.breed = "Labrador Retriever";
console.log(dog);
// { name: "Doug", breed: "Labrador Retriever" }
Copying objects
Shallow vs Deep Copy
Copying objects with the
Spread Operator
const originalBooking = {
airline: "United",
departure: "Albany",
destination: "Chicago"
};
const booking = { ...originalBooking, airline: "Delta", checkedLuggage: 0 };
console.log(booking);
/**
* {
* airline: "Delta",
* departure: "Albany",
* destination: "Chicago",
* checkedLuggage: 0
* }
*/
Review
const graduate = {
// Level 1: Copy by value
name: "Eddie Willard",
graduationYear: "2019",
skills: [/* Level 2: Copy by reference */ "JavaScript", "React", "CSS"],
links: {
// Level 2: Copy by reference
github: "https://github.com/example/profile",
linkedIn: "https://linkedin.com/profile"
}
};
const newGraduate = {...graduate};
// This does NOT change the original
// because the top level is copied by value
newGraduate.graduationYear = "2021";
// This DOES change the original
// because the nested levels are copied by reference
newGraduate.skills.push("SASS");
newGraduate.links.github = "https://github.com/newhandle/profile";
console.log(graduate);
/**
* {
* name: "Eddie Willard",
* graduationYear: "2019",
* skills: ["JavaScript", "React", "CSS", "SASS"],
* links: {
* github: "https://github.com/newhandle/profile",
* linkedIn: "https://linkedin.com/profile"
* }
* }
*/Most methods of copying objects, including the spread operator, will create a shallow copy.
↓ Scroll down
Deep Copy with
structuredClone
const graduate = {
// Level 1: Copy by value
name: "Eddie Willard",
graduationYear: "2019",
skills: [/* Level 2: Copy by reference */ "JavaScript", "React", "CSS"],
links: {
// Level 2: Copy by reference
github: "https://github.com/example/profile",
linkedIn: "https://linkedin.com/profile",
},
};
const newGraduate = structuredClone(graduate);
// This DOES not change the original because it is a deep copy
newGraduate.skills.push("SASS");
newGraduate.links.github = "https://github.com/newhandle/profile";
console.log(graduate);
/**
* {
* name: "Eddie Willard",
* graduationYear: "2019",
* skills: ["JavaScript", "React", "CSS"],
* links: {
* github: "https://github.com/example/profile",
* linkedIn: "https://linkedin.com/profile"
* }
* }
*/
↓ Scroll down
structuredClone came out in 2022. If you are working in older code bases, you may see them use third party libraries like Immer.js, Immutable.js, Lodash's cloneDeep or jQuery's extend to deep clone objects and arrays.
Callbacks
For Loop (Review)
Runs a block of code a specified number of times
for (let i = 0; i < 10; i++) {
// This says "Hello World" 10 times
console.log("Hello World");
}Step 1
Step 2
Step 3
Step 1 Create a counter
Step 2 Create a condition of when to stop
What is inside of the { } repeats
Step 3 Update the counter
A callback is a function that accepts another function as a parameter
Without Callbacks
const sendMessageConsole = (message) => {
console.log(message); // print message to console
};
const sendMessageAlert = (message) => {
alert(message); // an alert will open saying "print message using the built in alert"
};
sendMessageConsole('print message to console');
sendMessageAlert('print message using the built in alert');
With Callbacks
const displayMessage = (message, callback) => {
callback(message);
};
displayMessage("win", console.log); // win
displayMessage("win", alert); // alert that says "win"
Callbacks can be a reference to a function or an anonymous function.
const greet = (name, formatter) => {
return "Hello " + formatter(name);
};
const lowerCaseName = (name) => {
return name.toLowerCase();
};
const greeting = greet("Tim", lowerCaseName);
console.log(greeting); // Hello tim
const greet = (name, formatter) => {
return "Hello " + formatter(name);
};
const greeting = greet("Tim", (name) => {
return name.toLowerCase();
});
console.log(greeting);
Function reference
Anonymous function
What are callbacks used for?
- Looping through arrays
- Browser events (e.g. click event)
- Asynchronous code
const slides = [
"Intro to JavaScript",
"Collections",
"A Closer Look at Functions"
];
for (let i=0; i < slides.length; i++) {
const slide = slides[i];
console.log(`${i+1}. ${slide}`);
}
// 1. Intro to JavaScript
// 2. Collections
// 3. A Closer Look at Functions
Given this, how would complete this using a high order function that takes in a callback?
const slides = [
"Intro to JavaScript",
"Collections",
"A Closer Look at Functions"
];
const printSlides = (slide, i) => {
console.log(`${i+1}. ${slide}`);
};
slides.forEach(printSlides);
// 1. Intro to JavaScript
// 2. Collections
// 3. A Closer Look at FunctionsYou can use a forEach function.
Array.forEach()
Loops through and performs a callback on each item in an array
const myCallback = (item, index, array) => {
// You write the code to perform an action on each item here
console.log(item); // Single item in the array
// 1st time around, prints "myString"
// 2nd time around, prints 500
console.log(index); // Position (where) in array
// 1st time around, prints 0
// 2nd time around, prints 1
// 3rd time around, prints 2
console.log(array); // Entire array
// Everytime around, prints ["myString", 5]
}
const myArray = ["myString", 500, myVariable];
myArray.forEach(myCallback);
Alternatively, you can write forEach function like this, with an anonymous function:
["myString", 500, myVariable].forEach( (item, index, array) => {
// You write the code to perform an action on each item here
console.log(item);
});
["Intro to JavaScript", "Collections", "A Closer Look at Functions"].forEach(
(slide, i) => {
console.log(`${i + 1}. ${slide}`);
}
);
// 1. Intro to JavaScript
// 2. Collections
// 3. A Closer Look at Functions
const oldArray = ["1", "2", "3"];Array.map()
copies an array and transforms each item in the original array into something new
const newArray = [1, 2, 3];const oldArray = ["myString", 500];
const newArray = oldArray.map( (item, index, array) => {
console.log(item); // 1st time around, prints "myString"
console.log(index); // 1st time around, prints 0
console.log(array); // Everytime around, prints ["myString", 5]
// ...
});
// ...
map is similar to forEach,
const oldArray = ["myString", 500];
const newArray = oldArray.map( (item, index, array) => {
const newItem = /* Write code to change each item here */
return newItem; // Return the new version of the item
});
console.log(newArray); // Prints new array with changed items
map is similar to forEach, but map differs from forEach because it creates a new array from whatever you return.
const oldArray = ["1", "2", "3"];
const newArray = oldArray.map( (item, index, array) => {
const num = parseInt(item);
return num;
});
console.log(newArray); // [1, 2, 3]
const slides = ["Intro to JavaScript", "Collections", "A Closer Look at Functions"].map(
(slide, i) => {
return `${i + 1}. ${slide}`;
}
);
console.log(slides);
// [ "1. Intro to JavaScript", "2. Collections", "3. A Closer Look at Functions" ];
Do I keep?
Or do I toss?
Array.filter()
creates a new array by removes the values that you don't want from the original array
const oldArray = ["myString", 500];
const newArray = oldArray.filter( (item, index, array) => {
if (/* ... */) {
return true; // Keep this
} else {
return false; // Toss this
}
});
console.log(newArray); // Prints new array with some items removed
| forEach() | map() | filter() |
|---|---|---|
| Loops through each item in an array | Loops through each item in an array | Loops through each item in an array |
| Returns undefined | Returns a new array | Returns a new array |
| Use to access and do something with each item in an array | Use to copy and change each item in an existing array | Use to copy and remove unwanted items from an existing array |
More on arrays and callbacks
There are more methods that you can use. You can find them in MDN:
Function Chaining
Function Chaining
a pattern in JavaScript where multiple functions are called upon a value consecutively
value.function1().function2().function3() ...// Without chaining
// (Open me in browser console)
const timeNumbers = [1, 6, 8];
const timeStrings = timeNumbers.map((time) => {
return `- ${time}:00 PM`;
});
const list = timeStrings.join("\n"); // The "\n" creates a new line
console.log(list);
// - 1:00 PM
// - 6:00 PM
// - 8:00 PM
// With chaining
// (Open me in browser console)
const movieTimes = [1, 6, 8]
.map((time) => `- ${time}:00 PM`)
.join("\n"); // The "\n" creates a new line
console.log(movieTimes);
// - 1:00 PM
// - 6:00 PM
// - 8:00 PM
Without chaining
Function chaining
Each function in a chain must return a value in order to work
let movieTimes = [];
[1, 6, 8]
.forEach((time) => {
movieTimes.push(`- ${time}:00 PM`);
})
.join("\n"); // Error: Cannot read properties of undefined
The code above does not work because .forEach() does not return an array (it returns undefined).
You can chain all data types, not just arrays.
const userInput = "the great gatsby"; // string
const title = userInput
.replace("the ", "") // returns string
.concat(", The") // returns string
.split(" ") // returns array
.map((word) => word[0].toUpperCase() + word.substring(1)) // returns array
.join(" "); // return string
console.log(title); // Great Gatsby, The
Promises
Synchronous
Things happen one at a time, in a predictable order. When you call a function that performs a long-running action, it returns only when the action has finished and it can return the result. This stops your program for the time the action takes.
Asynchronous
Multiple things happen at the same time, in an unpredictable order. When you start an action, your program continues to run.
Big Words Alert!
Synchronous
Everything else
Asynchronous
- Timers (e.g. window.setTimeout)
- Promises
- HTTP Requests (AJAX)
- Some media and file handling tasks
- Streams and pipes in Node.js
What is
What is

Philip Roberts: What the heck is the event loop anyways?
Styles of handling asynchronous code in JavaScript:
- Callbacks
- Promises
- Async & Await
window.setTimeout
a timer; delays a function from being invoked for a given amount of time
window.setTimeout(() => {
// code that is delayed
}, 1000); // amount of time to wait in millisecondsWhat is the response below?
let data;
// window.setTimeout delays a function from being called on
// for a given amount of time
window.setTimeout(() => {
// All code that should be delayed goes in here
data = { success: true };
}, 1000); // Delaying by 1000 milliseconds (1 second)
console.log(data); // What is this?We solve this using promises like this:
function delay(milliseconds) {
return new Promise((resolve) => {
window.setTimeout(resolve, milliseconds);
});
}
let data;
delay(1000) // Delay for 1000 milliseconds (1 second)
.then(() => {
data = { success: true };
return data;
})
.then((result) => {
console.log(result); // Logs { success: true } after 1 second
});Promises
asyncFunction()
.then(response => /* ... */) // success function
.then(response => /* ... */) // which can be chained
.then(response => /* ... */) // as long as it
.then(response => /* ... */) // returns another promise
.catch((error) => /* ... */); // error handlerTurning your code into a promise with the
Promise API
const asyncColorChanger = (color) => {
// Wrapping in a promise so that I can chain with .then()
return new Promise((resolve, reject) => {
// Waits for 1 second
window.setTimeout(() => {
const h1 = document.querySelector('h1');
// Changes the color
h1.style.color = color;
// Moves on to the function inside of the next .then()
resolve(color);
}, 1000);
});
};
asyncColorChanger('red')
.then(() => asyncColorChanger('orange'))
.then(() => asyncColorChanger('#EBEB00'))
.then(() => asyncColorChanger('green'))
.then(() => asyncColorChanger('blue'))
.then(() => asyncColorChanger('purple'));const asyncFunction = () => {
return new Promise((resolve, reject) {
if (condition) resolve(/* ... */); // the .then() below
else reject(); // the .catch() below
}
};
asyncFunction()
.then(data => /* ... */) // when resolve (success)
.catch(() => /* ... */); // when reject (error)↓ Scroll down
References & Resources
-
Understanding Scope in JavaScript https://scotch.io/tutorials/understanding-scope-in-javascript
-
Closures
-
Secrets of the JavaScript Ninja, John Resig, Bear Bibeault, 2013
-
https://medium.freecodecamp.org/javascript-closures-simplified-d0d23fa06ba4
-
-
A Beginner’s Guide to Currying in Functional JavaScript https://www.sitepoint.com/currying-in-functional-javascript/
-
Array Methods https://javascript.info/array-methods
-
Reduce https://www.airpair.com/javascript/javascript-array-reduce
-
Function Chaining https://medium.com/technofunnel/javascript-function-chaining-8b2fbef76f7f
Week 7
By Jamal Taylor
Week 7
- 218
