let
, const
(can't redeclare, hoisting, block scope)for...of
loops (array, map, set)...
returns array, spread vs apply)class
keywordsuper
and extends
keywordsObject.assign
, Array.from
, find
, findIncdex
, includes
, Number.isFinite
)const: declare constant
const numbers = [1,2,3,4];
numbers.push(5);
numbers;
// numbers = "no!" //TypeError
let: create a new kind of scope besides global and function
Global scope
var global = 1; global //1
Function scope
function test(){
var fnVariable = "secret";
}
test //undefined
// fnVariable //Error: fnVariable is not defined
Hoisting
function helloInstructor(){
return elie;
var elie = "Me!";
}
helloInstructor(); //undefined
function helloSecondInstructor(){
return colt;
let colt = "HIM!";
}
// helloSecondInstructor(); //ReferenceError
Common Use Case for 'let'
// for(var i = 0; i < 5; i++){
// setTimeout(function(){
// console.log(i);
// },1000)
// }
By the time the setTimeout runs, the for loop has already finished running and the value of i has been incremented to 5 and the loop has stopped. Only then does setTimeOut run
Before the 'let' keyword , the solution to this was to run another function inside the loop and invoke it immediately so that each setTimeout will have its own value of i.
// for(var i = 0; i < 5; i++){
// (function(j){
// setTimeout(function(){
// console.log(j);
// },1000);
// })(i)
// }
// 0
// 1
// 2
// 3
// 4
Immediately-invoked function expression (IIFE) (tricky)
Function expression
// functionOne(); //Output: undefined is not a function
var functionOne = function() {
console.log("Hello!");
};
Function declaration
functionTwo(); // Output: "Hello!"
function functionTwo() {
console.log("Hello!");
}
Refactor with 'let'
// for(let i = 0; i < 5; i++){
// setTimeout(function(){
// console.log(i);
// },1000);
// }
// 0
// 1
// 2
// 3
// 4
Example: Concatenate Strings
var firstName = "Elie";
var lastName = "Schoppik";
console.log(`Hello${firstName}${lastName}`);
console.log(`Hello ${firstName} ${lastName}`);
Example: Multi-Line Strings
/*output: syntax error
"
Hello
"
*/
It works!
`
Hello
Elie!
`
- from: `function fn(a,b) {}`
- to : `fn = (a,b) => {}`
b) for anonymous function
- from: `function (a,b) {}`
- to : `() => {}`
2) One-line arrow functionthis
and 'arguments' (use rest
instead) (tricky)Example: Arrow Functions with Function Expression
ES5
var add = function(a,b){
return a+b;
}
ES2015
var add = (a,b) => {
return a+b;
}
Example: One-line Arrow Functions: Example 1
Continue from example above
var add = (a,b) => a+b;
One-line Arrow Functions: Example 2 (map)
ES5
[1,2,3].map(function(value){
return value * 2;
});
ES2015
[1,2,3].map(value => value * 2);
Example: One-line Arrow Functions: Example 3 (map & filter)
Before ES2015
function doubleAndFilter(arr){
return arr.map(function(value){
return value * 2;
}).filter(function(num){
return num % 3 === 0;
})
};
doubleAndFilter([5,10,15,20]);
ES2015
var doubleAndFilter = arr => arr.map(val => val * 2).filter(num => num % 3 === 0);
doubleAndFilter([5,10,15,20]);
Problem in Arrow Functions: 'this' Arrow functions do not have their own keyword this
var instructor = {
firstName: "Elie",
//this refer to the enclosing context i.e. global object
sayHi: () => 'Hello ${this.firstName}'
}
instructor.sayHi();
Using 'this' with Arrow Functions
Before ES2015: use bind
var instructor = {
firstName: "Elie",
sayHi: function(){
setTimeout(function(){
console.log("Hello " + this.firstName);
}.bind(this), 1000);
}
}
instructor.sayHi();
ES2015
setTimeOut
functionthis
refers to the enclosing context (the instructor object).var instructor = {
firstName: "Elie",
sayHi: function(){
setTimeout(() => {
console.log("Hello " + this.firstName);
}, 1000);
}
}
instructor.sayHi();
We used both the function keyword and an arrow function - why? Can we use arrow function for the sayHi method as well? If we use an arrow function on the sayHi method, the sayHi method will not not have its own keyword this and the keyword this refers to the enclosing context (i.e. the global object - window)
var instructor = {
firstName: "Elie",
sayHi: () => {
setTimeout(() => {
console.log("Hello " + this.firstName);
}, 1000);
}
}
instructor.sayHi();
Using 'arguments' with Arrow Functions Arrow functions do not have their own keyword 'arguments'
// var add = (a,b) => {
// return arguments;
// }
// add(2,4); // ReferenceError: arguments is not defined
If the arrow function is inside of another function, it will be the outer function arguments
function outer() {
return innerFunction = () => {
return arguments;
}
}
outer(1)(2);
Exercise Arrow Functions
1 - Refactor the following code to use ES2015 one-line arrow functions - make sure your function is also called tripleAndFilter
function tripleAndFilter(arr){
return arr.map(function(value){
return value * 3;
}).filter(function(value){
return value % 5 === 0;
})
}
Can't find variable xxx if let is not used
let tripleAndFilter = arr => arr.map(value => value * 3).filter(value => value % 5 === 0);
2 - Refactor the following code to use ES2015 one-line arrow functions. Make sure your function is also called doubleOddNumbers
function doubleOddNumbers(arr){
return arr.filter(function(val){
return val % 2 !== 0;
}).map(function(val){
return val *2;
})
}
let doubleOddNumbers = arr => arr.filter(val => val % 2 !== 0).map(val => val *2);
3 - Refactor the following code to use ES2015 arrow functions. Make sure your function is also called mapFilterAndReduce.
function mapFilterAndReduce(arr){
return arr.map(function(val){
return val.firstName
}).filter(function(val){
return val.length < 5;
}).reduce(function(acc,next){
acc[next] = next.length
return acc;
}, {})
}
let mapFilterAndReduce = (arr) => arr.map(val => val.firstName).filter(val => val.length < 5).reduce((acc,next) => {
acc[next] = next.length;
return acc;
}, {});
4 - Write a function called createStudentObj which accepts two parameters, firstName and lastName and returns an object with the keys of firstName and lastName with the values as the parameters passed to the function.
Example:
createStudentObj('Elie', 'Schoppik') // {firstName: 'Elie', lastName: 'Schoppik'}
Pre ES2015
// function createStudentObj(firstName, lastName){
// return {firstName: firstName, lastName: lastName};
// }
ES2015
// let createStudentObj = (firstName, lastName) => ({firstName: firstName, lastName: lastName});
5 - Given the following code: Refactor this code to use arrow functions to make sure that in 1000 milliseconds you console.log 'Hello Colt'
var instructor = {
firstName: "Colt",
sayHi: function(){
setTimeout(function(){
console.log('Hello ' + this.firstName)
},1000)
}
}
var instructor = {
firstName: "Colt",
sayHi: function(){
setTimeout(() => console.log('Hello ' + this.firstName), 1000);
}
}
Before ES2015
function add(a, b){
return a+b;
}
add(); // NaN because a is undefined and b is undefined
ES2015
function add(a=10, b=20){
return a+b;
}
add();
add(20);
var arr = [1,2,3,4,5];
for(let val of arr){
console.log(val);
}
ES5
function sumArguments(){
var total = 0;
for(var i = 0; i < arguments.length; i++){
total += arguments[i];
}
return total;
}
A little fancier ES5
function sumArguments(){
var argumentsArray = [].slice.call(arguments);
return argumentsArray.reduce(function(accumulator,nextValue){
return accumulator + nextValue;
});
}
ES2015
function sumArguments(...args){
return args.reduce((acc, next) => acc + next);
}
ES2015 (simpler)
var sumArguments = (...args) => args.reduce((acc, next) => acc + next);
Spread and CSV ES5
var arr1 = [1,2,3];
var arr2 = [4,5,6];
var arr3 = [7,8,9];
Difference between + and concat on arrays
var combined = arr1.concat(arr2).concat(arr3);
combined;
var combined = arr1 + arr2 + arr3;
combined
ES2015
var combined = [...arr1, ...arr2, ...arr3];
combined
Spread instead of Apply
var arr = [3,2,4,1,5];
Math.max(arr); // NaN
ES5
Math.max.apply(this, arr);
ES2015
Math.max(...arr);
How can we invoke sumValues as a function using nums as a parameter?
function sumValues(a,b,c){
return a+b+c;
}
var nums = [12,15,20];
ES5
sumValues.apply(this, nums);
ES2015
sumValues(...nums);
Exercise: Rest and Spread Write a function called smallestValue which accepts a variable number of parameters and returns the smallest parameters passed to the function.
Examples:
smallestValue(4,1,12,0) // 0
smallestValue(5,4,1,121) // 1
smallestValue(4,2) // 2
smallestValue(99,12321,12.2) // 2
function smallestValue(...args){
return Math.min(...args);
}
Write a function called placeInMiddle which accepts two parameters, an array and another array. This function should return the first array with all of the values in the second array placed in the middle of the first array.
Examples:
placeInMiddle([1,2,6,7],[3,4,5]) // [1,2,3,4,5,6,7]
placeInMiddle([1],[3,4,5]) // [3,4,5,1]
placeInMiddle([1,6],[2,3,4,5]) // [1,2,3,4,5,6]
placeInMiddle([],[2,3,4,5]) // [2,3,4,5]
function placeInMiddle(arr, vals){
return [...arr.slice(0, arr.length/2), ...vals, ...arr.slice(arr.length/2)];
}
Alternative
function placeInMiddle(arr, vals){
let mid = Math.floor(arr.length/2)
arr.splice(mid,0,...vals)
return arr;
}
Write a function called joinArrays which accepts a variable number of parameters (you can assume that each argument to this function will be an array) and returns an array of all of the parameters concatenated together
Examples:
joinArrays([1],[2],[3]) // [1,2,3]
joinArrays([1],[2],[3],[1],[2],[3]) // [1,2,3,1,2,3]
joinArrays([1,2,3],[4,5,6],[7,8,9]) // [1,2,3,4,5,6,7,8,9]
joinArrays([1],[3],[0],[7]) // [1,3,0,7]
function joinArrays(...args){
return args.reduce((acc, next) => acc.concat(next), [])
}
Write a function called sumEvenArgs which takes all of the parameters passed to a function and returns the sum of the even ones.
Examples:
sumEvenArgs(1,2,3,4) // 6
sumEvenArgs(1,2,6) // 8
sumEvenArgs(1,2) // 2
function sumEvenArgs(...args){
return args.reduce((acc, next) => next % 2 === 0 ? acc += next : acc, 0)
}
Write a function called flip which accepts a function and a value for the keyword this. Flip should return a new function that when invoked, will invoke the function passed to flip with the correct value of the keyword this and all of the parameters passed to the function REVERSED. HINT - if you pass more than two parameters to flip, those parameters should be included as parameters to the inner function when it is invoked. You will have to make use of closure!
Examples: Example 1
function personSubtract(a,b,c){
return this.firstName + " subtracts " + (a-b-c);
}
var person = {
firstName: 'Elie'
}
var flipFn = flip(personSubtract, person);
flipFn(3,2,1) // "Elie subtracts -4"
var flipFn2 = flip(personSubtract, person, 5,6);
flipFn(7,8). // "Elie subtracts -4"
Example 2
function subtractFourNumbers(a,b,c,d){
return a-b-c-d;
}
flip(subtractFourNumbers,this,1)(2,3,4) // -2
flip(subtractFourNumbers,this,1,2)(3,4) // -2
flip(subtractFourNumbers,this,1,2,3)(4) // -2
flip(subtractFourNumbers,this,1,2,3,4)() // -2
flip(subtractFourNumbers,this)(1,2,3,4) // -2
flip(subtractFourNumbers,this,1,2,3)(4,5,6,7) // -2
flip(subtractFourNumbers,this)(1,2,3,4,5,6,7,8,9,10) // -2
flip(subtractFourNumbers,this,11,12,13,14,15)(1,2,3,4,5,6,7,8,9,10) // -22
function flip(fn, thisArg, ...outerArgs){
return function(...innerArgs){
let allArgs = outerArgs.concat(innerArgs).slice(0, fn.length);
return fn.apply(thisArg, allArgs.reverse());
}
}
Write a function called bind which accepts a function and a value for the keyword this. Bind should return a new function that when invoked, will invoke the function passed to bind with the correct value of the keyword this. HINT - if you pass more than two parameters to bind, those parameters should be included as parameters to the inner function when it is invoked. You will have to make use of closure!
Example 1:
function firstNameFavoriteColor(favoriteColor){
return this.firstName + "'s favorite color is " + favoriteColor
}
var person = {
firstName: 'Elie'
}
var bindFn = bind(firstNameFavoriteColor, person);
bindFn('green') // "Elie's favorite color is green"
var bindFn2 = bind(firstNameFavoriteColor, person, 'blue');
bindFn2('green') // "Elie's favorite color is blue"
Example 2:
function addFourNumbers(a,b,c,d){
return a+b+c+d;
}
bind(addFourNumbers,this,1)(2,3,4) // 10
bind(addFourNumbers,this,1,2)(3,4) // 10
bind(addFourNumbers,this,1,2,3)(4) // 10
bind(addFourNumbers,this,1,2,3,4)() // 10
bind(addFourNumbers,this)(1,2,3,4) // 10
bind(addFourNumbers,this)(1,2,3,4,5,6,7,8,9,10) // 10
function bind(fn, thisArg, ...outerArgs){
return function(...innerArgs){
return fn.apply(thisArg, [...outerArgs, ...innerArgs]);
}
}
1) Object Shorthand Notation
2) Object Methods
function
keyword and place () after the name of the method3) Computed Property Names
var firstName = "Elie";
var lastName = "Schoppik";
ES5
var instructor = {
firstName: firstName,
lastName: lastName
}
ES2015
var instructor = {
firstName,
lastName
}
ES5
var instructor = {
sayHello: function(){
return "Hello!";
}
}
ES2015
var instructor = {
sayHello(){
return "Hello!";
}
}
ES5
var firstName = "Elie";
var instructor = {};
instructor[firstName] = "That's me!";
instructor.Elie;
ES2015
var firstName = "Elie";
var instructor = {
// add brackets around the name of the key to let Javascript compute the name of the property
[firstName]: "That's me!"
}
instructor.Elie;
Exatract Values
var instructor = {
firstName: "Elie",
lastName: "Schoppik"
}
ES5
var firstName = instructor.firstName;
var lastName = instructor.lastName;
firstName;
lastName;
ES2015
var {firstName, lastName} = instructor;
firstName;
lastName;
If you don't want to name the variables with the same names as the key in the object, you can simply add a colon and a new variable name
var {firstName: first, lastName:last} = instructor;
first;
last;
Default Vales with an Object
ES5
function createInstructor(options){
var options = options || {}; //if options parameters not passed in, assign it to an empty object
var name = options.name || {first: "Matt", last:"Lane"}
var isHilarious = options.isHilarious || false;
return [name.first, name.last, isHilarious];
}
createInstructor();
createInstructor({isHilarious:true});
createInstructor({name: {first:"Tim", last:"Garcia"}});
ES2015
function createInstructor({name = {first:"Matt", last:"Lane"}, isHilarious=false } = {}){
return [name.first, name.last, isHilarious];
}
createInstructor();
createInstructor({isHilarious:true});
createInstructor({name: {first:"Tim", last:"Garcia"}});
Object fields as parameters
ES5
function displayInfo(obj) {
return [obj.name, obj.favColor];
}
var instructor = {
name: "Elie",
favColor: "Purple"
};
displayInfo(instructor);
ES2015
function displayInfo({name, favColor}) {
return [name, favColor];
}
var instructor = {
name: "Elie",
favColor: "Purple"
};
displayInfo(instructor);
var arr = [1,2,3];
ES5
var a = arr[0];
var b = arr[1];
var c = arr[2];
a;
b;
c;
ES2015
var arr = [1,2,3];
var [a,b,c] = arr;
a;
b;
c;
function returnNumbers(a,b) {
return [a,b];
}
ES5
var first = returnNumbers(5,10)[0];
var second = returnNumbers(5,10)[1];
first;
second;
ES2015
var [first, second] = returnNumbers(5,10);
first;
second;
Swapping Values
ES5
function swap(a,b){
var temp = a;
a = b;
b = temp;
return [a,b];
}
swap(10,5);
ES2015
function swap(a,b){
[a,b] = [b,a];
return [a,b]
}
swap(10,5);
Exercise: Destructuring
Write a function called displayStudentInfo which accepts an object and returns the string "Your full name is" concatenated with the value of the first key and a space and then the value of the last key. See if you can destructure this object inside of the function.
Examples:
displayStudentInfo({first: 'Elie', last:'Schoppik'}) // 'Your full name is Elie Schoppik')
function displayStudentInfo(obj){
var {first, last} = obj;
return `Your full name is ${first} ${last}`;
}
Write a function called printFullName which accepts an object and returns the string "Your full name is" concatenated with the value of the first key and a space and then the value of the last key. See if you can destructure this object DIRECTLY from the parameters. The output of the printFullName function should be the exact same as the displayStudentInfo function.
Examples:
printFullName({first: 'Elie', last:'Schoppik'}) // 'Your full name is Elie Schoppik'
You will have to pass in the correct parameters for this function!
function printFullName({first, last} = {}){
return `Your full name is ${first} ${last}`;
}
Write a function called createStudent which accepts as a parameter, a default parameter which is a destructured object with the key of likesES2015 and value of true, and key of likesJavaScript and value of true.
If both the values of likesJavaScript and likesES2015 are true, the function should return the string 'The student likes JavaScript and ES2015'. If the value of likesES2015 is false the function should return the string 'The student likes JavaScript!' If the value of likesJavaScript is false the function should return the string 'The student likesES2015!' If both the value of likesJavaScript and likesES2015 are false, the function should return the string 'The student does not like much...'
Examples:
createStudent() // 'The student likes JavaScript and ES2015')
createStudent({likesES2015:false}) // 'The student likes JavaScript!')
createStudent({likesJavaScript:false}) // 'The student likes ES2015!')
createStudent({likesJavaScript:false, likesES2015:false}) // 'The student does not like much...')
You will have to pass in the correct parameters for this function!
function createStudent({likesES2015=true, likesJavaScript=true} = {}){
if (likesJavaScript && likesES2015){
return 'The student likes JavaScript and ES2015!';
}
if (likesES2015){
return 'The student likes ES2015!';
}
if (likesJavaScript){
return 'The student likes JavaScript!';
}
return 'The student does not like much...';
}
Write a function called reverseArray which accepts an array and returns the array with all values reversed. See if you can do this without creating a new array! (tricky)
Examples:
reverseArray([1,2,3,4,5]) // [5,4,3,2,1]
reverseArray([1,2]) // [2,1]
reverseArray([]) // []
reverseArray([1,2,3,4,5,6,7,8,9,10]) // [10,9,8,7,6,5,4,3,2,1]
function reverseArray(arr){
for(var i = 0; i < arr.length/2; i++){
[arr[i], arr[arr.length - 1 - i]] = [arr[arr.length - 1 - i], arr[i]];
}
return arr;
}
Alternative
function reverseArray(arr){
return arr.reverse();
}
Guess Password Refactoring
let
and const
variableslet
keyword inside our loops
2) use template strings
3) use arrow functionElement.classList https://developer.mozilla.org/en-US/docs/Web/API/Element/classList
new
keyword to create objectES5
// function Student(firstName, lastName){
// this.firstName = firstName;
// this.lastName = lastName;
// }
// var elie = new Student('Elie', 'Schoppik');
ES2015
// class Student {
// constructor(firstName, lastName){
// this.firstName = firstName;
// this.lastName = lastName;
// }
// }
// var elie = new Student('Elie', 'Schoppik'); // same as ES5
ES5
// function Student(firstName, lastName){
// this.firstName = firstName;
// this.lastName = lastName;
// }
// Student.prototype.sayHello = function(){
// return "Hello " + this.firstName + " " + this.lastName;
// }
ES2015
// class Student {
// constructor(firstName, lastName){
// this.firstName = firstName;
// this.lastName = lastName;
// }
// sayHello(){
// return `Hello ${this.firstName} ${this.lastName}`;
// }
// }
Array.isArray()
, Object.create()
, Object.freeze()
, Object.assign
(ES2015), Array.from
(ES2015), Number.isFinite
(ES2015) (see below)ES5 Class methods are placed directly on the constructor function
// function Student(firstName, lastName){
// this.firstName = firstName;
// this.lastName = lastName;
// }
// Student.isStudent = function(obj){
// return obj.constructor === Student;
// }
ES2015
class Student {
constructor(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
sayHello(){
return `Hello ${this.firstName} ${this.lastName}`;
}
static isStudent(obj){
return obj.constructor === Student;
}
}
Usage
var s = new Student('E', 'S');
Student.isStudent(s);
Student.isStudent(s);
Static Method Example: Array.isArray()*
typeof [];
Array.isArray([]);
ES5 Inheritance Example: Passing the method sayHello() from Person to Student
function Person(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.sayHello = function(){
return "Hello " + this.firstName + " " + this.lastName;
}
function Student(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
Set the prototype property of a constructor to be an object created from another prototype property
Student.prototype = Object.create(Person.prototype);
// Reset the constructor property on a constructor function
Student.prototype.constructor = Student;
ES2015 Inheritance
class Person {
constructor(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
sayHello(){
return `Hello ${this.firstName} ${this.lastName}`;
}
}
Use the 'extends' keyword
class Student extends Person {
}
Check if Student have method sayHello
Student.prototype.sayHello;
Check if Student has its own constructor
Student.prototype.constructor === Student;
super([arg])
; // calls the parent constructorES5
function Person(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.sayHello(){
return "Hello " + this.firstName + " " + this.lastName;
}
function Student(){
Person.apply(this, arguments); // use apply in ES5
}
ES2015
class Person {
constructor(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
sayHello(){
return `Hello ${this.firstName} ${this.lastName}`;
}
}
class Student extends Person {
constructor(firstName, lastName){
super(firstName, lastName); // use super in ES2015
}
}
Exercise: Inheritance and Super
1 - Create a class for for a Vehicle. Each vehicle should have a make, model and year property.
2 - Add an instance method called start which returns the string "VROOM!"
3 - Add an instance method called toString which returns the string "The make, model, and year are" concatenated with the make, model and year property
Examples
var vehicle = new Vehicle("Tractor", "John Deere", 1999)
vehicle.toString() // 'The make, model, and year are Tractor John Deere 1999'
class Vehicle {
constructor(make, model, year){
this.make = make;
this.model = model;
this.year = year;
}
start(){
return 'VROOM!';
}
toString(){
return `The make, model, and year are ${this.make} ${this.model} ${this.year}`;
}
}
4 - Create a class for a Car. Each object created from the Car function should also have a make, model, and year and a property called numWheels which should be 4. The Car prototype should inherit all of the methods from the Vehicle prototype
class Car extends Vehicle {
constructor(){
super(...arguments) // rest
this.numWheels = 4;
}
}
5 - Create a class for a Motorcycle. Each object created from the Motorcycle function should also have a make, model, and year and a property called numWheels which should be 2. The Motorcycle prototype should inherit all of the methods from the Vehicle prototype
class Motorcycle extends Vehicle {
constructor(){
super(...arguments) // rest
this.numWheels = 2;
}
}
Symbol.iterator
which means we can use a for...of loop!.entries()
and destructuringvar firstMap = new Map;
firstMap.set(1, 'Elie');
firstMap.set(false, 'a boolean');
firstMap.set('nice', 'a string');
firstMap.delete('nice');
firstMap.size;
key can be of any type!
var arrayKey = [];
firstMap.set(arrayKey, [1,2,3,4,5]);
var objectKey = {};
firstMap.set(objectKey, {a:1});
Extracting Values
firstMap.get(1);
firstMap.get(false);
firstMap.get(arrayKey);
firstMap.get(objectKey);
Iterating over Map
firstMap.forEach(v => console.log(v));
firstMap.values();
firstMap.keys();
Accessing Keys and Values in a Map
We can access everything with .entries()
and destructuring
var m = new Map;
m.set(1, 'Elie');
m.set(2, 'Colt');
m.set(3, 'Tim');
for(let [key,value] of m.entries()){
console.log(key, value);
}
var s = new Set;
s
Can also be created from an array
var s2 = new Set([3,1,4,1,2,1,5]);
s2
s.add(10);
s;
s.add(20);
s;
s.add(10);
s;
s.size;
s.has(10);
s.delete(20);
s.size;
// s2[Symbol.iterator]; // function(){}...
// we can use a for...of loop!
Exercise: Map and Set
class MessageBoard {
In your constructor method, you should assign two properties for each object created from the MessageBoard class. The first should be a property called messages which is an empty Map, and the second is a property called id which has a value of 1.
var m = new MessageBoard
m.hasOwnProperty('messages') // true
m.messages.constructor // function Map() { [native code] }
m.hasOwnProperty('id') // true
m.id // 1
constructor(){
this.messages = new Map;
this.id = 1;
}
Add a method called addMessage which accepts a string. The function should add a key and value to the messages map with a key of whatever the value of this.id is and a value of whatever the string is that is passed to the function. The function should return the object created from the class so that the method can be chained. (HINT - to implement the last part, make sure to return this).
var m = new MessageBoard
m.addMessage('hello');
m.messages.size // 1
m.addMessage('awesome!') // m
m.addMessage('awesome!').addMessage('nice!').addMessage('cool!')
To chain methods, you have to return the object by returning this , that way you can chain the method because the returned object will have that method.
addMessage(str){
this.messages.set(this.id, str);
this.id++;
return this; // tricky
}
Add a method called findMessageById which accepts a number and returns the message in the messages map with the same key as the number passed to the function. If the key is not found in the messages map, the function should return undefined.
var m = new MessageBoard
m.addMessage('hello!')
m.addMessage('hi!')
m.addMessage('whats up?')
m.findMessageById(1) // 'hello!'
m.findMessageById(2) // 'hi!'
m.findMessageById(3) // 'whats up?'
m.findMessageById(4) // undefined
m.findMessageById() // undefined
findMessageById(id){
return this.messages.get(id);
}
Add a method called findMessageByValue which accepts a string and returns the message in the messages map with the same value as the string passed to the function. If the value is not found in the messages map, the function should return undefined.
var m = new MessageBoard
m.addMessage('hello!')
m.addMessage('hi!')
m.addMessage('whats up?')
m.findMessageByValue('hello!') // 'hello!'
m.findMessageByValue('hi!') // 'hi!'
m.findMessageByValue('whats up?') // 'whats up?'
m.findMessageByValue('nothing here') // undefined
m.findMessageByValue() // undefined
findMessageByValue(str){
for (let msg of this.messages.values()){
if (msg === str) {
return str;
}
}
}
Add a method called removeMessage which accepts a number and removes a message in the messages map with a key of the number passed to the function.
var m = new MessageBoard
m.addMessage('hello!')
m.addMessage('hi!')
m.addMessage('whats up?')
m.removeMessage(1)
m.removeMessage(2)
m.messages.size // 1
m.removeMessage() // m
removeMessage(num){
this.messages.delete(num);
return this; //for method chaining
}
Add a method called numberOfMessages which returns the number of keys in the messages map
var m = new MessageBoard
m.addMessage('hello!')
m.addMessage('hi!')
m.addMessage('whats up?')
m.numberOfMessages() // 3
numberOfMessages(){
return this.messages.size;
}
Add a method called messagesToArray which returns an array of all of the values in the messages map
var m = new MessageBoard
m.addMessage('hello!')
m.addMessage('hi!')
m.addMessage('whats up?')
m.messagesToArray() // ['hello!', 'hi!', 'whats up?'])
messagesToArray(){
return Array.from(this.messages.values());
}
Alternative
messagesToArray(){
return [...this.messages.values()];
}
Write a function called uniqueValues which accepts an array and returns the number of unique values in the array
uniqueValues([1,1,2,2,2,3,3,3,3,4,4,4,5,5,6]) // 6
function uniqueValues(arr){
var s = new Set(arr);
return s.size;
}
Write a function called hasDuplicates which accepts an array and returns true if there are duplicate values in the array, otherwise it should return false.
hasDuplicates([1,1,2,2,2,3,3,3,3,4,4,4,5,5,6]) // true
hasDuplicates([1,2,3,4,5,6]) // false
hasDuplicates([]) // false
function hasDuplicates(arr){
let s = new Set(arr);
if (arr.length === s.size){
return false;
}
return true;
}
Tricky Write a function called countPairs which accepts an array of numbers and a number. The function should return the number of unique pairs (two numbers) that sum up to the number passed to the function.
countPairs([8,2,6,4,10,0],10) // 3
countPairs([8,2],10) // 1
countPairs([1,2],10) // 0
countPairs([1,2,3,4,5],10) // 0
countPairs([],10) // 0
countPairs([5,4,-10,6,-20,16],-4) // 2
countPairs([0,-4],-4) // 1
function countPairs(arr, num){
var cache = new Set(arr);
var count = 0;
for(let val of arr){
cache.delete(val); // prevent us from dealing with a pair of the same number
if(cache.has(num - val)){ // check if item exist in remaining set to sum to 2nd parameter
count++;
}
}
return count;
}
function displayAtRandomTime(){
return new Promise(function(resolve,reject){
setTimeout(function(){
if(Math.random() > .5) {
resolve('Yes!');
} else {
reject('No!');
}
},1000);
});
}
The returned value from a promise will always contain a .then and .catch method
displayAtRandomTime().then(function(value){ // .then: handle 'resolved'
console.log(value);
}).catch(function(error){ // .catch: handle 'reject'
console.log(error);
});
Since a promise always returns something that has a .then (thenable) - we can chain promises together and return values from one promise to another!
The following codes use jQuery and only works on website using jQuery with the console You can check whether a website use jQuery by typing 'jQuery' in the console. If you get an error it is not loaded on that page, if you see a function it is
var years = [];
$.getJSON('https://omdbapi.com?t=titanic&apikey=thewdb')
.then(function(movie){
years.push(movie.Year);
return $.getJSON('https://omdbapi.com?t=shrek&apikey=thewdb');
})
.then(function(movie){
years.push(movie.Year);
console.log(years);
})
console.log('ALL DONE!');
function getMovie(title){
return $.getJSON(`https://omdbapi.com?t=${title}&apikey=thewdb`);
}
var titanicPromise = getMovie('titanic');
var shrekPromise = getMovie('shrek');
var braveheartPromise = getMovie('braveheart');
Using Promise.all
Promise.all([titanicPromise, shrekPromise, braveheartPromise]).then(function(movies){
return movies.forEach(function(value){
console.log(value.Year);
});
});
// 1997
// 2001
// 1995
Exercise: Promises (Pending)
Hint - Try to use Promise.all to solve this and remember that the jQuery AJAX methods ($.getJSON, $.ajax, etc.) return a promise.
hasMostFollowers('elie','tigarcia','colt').then(function(data){
console.log(data)
});
// output: "Colt has the most followers with 424" */
starWarsString(1).then(function(data){
console.log(data)
})
// output: "Luke Skywalker" */
Bonus 1 - Using the data from the previous AJAX call above, make another AJAX request to get the first film that character is featured in and return a promise that when resolved will console.log the name of the character and the film they are featured in
starWarsString(1).then(function(data){
console.log(data)
})
// Output: "Luke Skywalker is featured in The Empire Strikes Back, directed by Irvin Kershner" */
Bonus 2 - Using the data from Bonus 1 - make another AJAX call to get the information about the first planet that the film contains. Your function should return a promise that when resolved will console.log the name of the character and the film they are featured in and the name of the planet.
starWarsString(1).then(function(data){
console.log(data)
})
// Output: "Luke Skywalker is featured in The Empire Strikes Back, directed by Irvin Kershner and it takes place on Hoth" */
*
value
and done
.yield
keywordSymbol.iterator
property we can use a for...of
loop! (example below)function* pauseAndReturnValues(num){
for(let i = 0; i < num; i++){
yield i;
}
}
var gen = pauseAndReturnValues(5);
gen.next();
gen.next();
gen.next();
gen.next();
gen.next();
gen.next();
Yielding Multiple Values
function* printValues(){
yield "First";
yield "Second";
yield "Third";
}
var g = printValues();
g.next().value;
g.next().value;
g.next().value;
Iterating over a Generator
function* pauseAndReturnValues(num){
for(let i = 0; i < num; i++){
yield i;
}
}
for(val of pauseAndReturnValues(3)){
console.log(val);
}
Async Generator
function* getMovieData(movieName){
console.log('starting')
yield $.getJSON(`https://omdbapi.com?t=${movieName}&apikey=thewdb`);
console.log('ending')
}
The next value returned is a promise so let's resolve it
var movieGetter = getMovieData('titanic');
movieGetter.next().value.then(val => console.log(val));
ES5
var o = {name: "Elie"};
var o2 = o;
Same reference - change properties of o2 affects o!
o2.name = "Tim";
o.name;
ES2015
var o = {name: "Elie"};
var o2 = Object.assign({},o);
o2.name = "Tim";
o.name;
Not a Deep Clone!
ES2015
var o = {instructors: ["Elie", "Tim"]}; //object inside object
var o2 = Object.assign({},o);
o2.instructors.push("Colt");
o.instructors;
var divs = document.getElementsByTagName("div"); // returns an array-like-object
var converted = [].slice.call(divs) // convert the array-like-object into an array
converted.reduce // function reduce() { ... }
ES2015
var divs = document.getElementsByTagName("div");
var converted = Array.from(divs);
ES2015
var firstSet = new Set([1,2,3,4,3,2,1]);
firstSet;
var arrayFromSet = Array.from(firstSet);
arrayFromSet;
var instructors = [{name: "Elie"}, {name: "Matt"}, {name: "Tim"}, {name: "Colt"}];
instructors.find(function(val){
return val.name === "Tim";
});
Similar to find, but returns an index or -1 if the value is not found
var instructors = [{name: "Elie"}, {name: "Matt"}, {name: "Tim"}, {name: "Colt"}];
instructors.findIndex(function(val){
return val.name === "Tim";
});
"awesome".indexOf("some") > -1;
ES2015
"awesome".includes("some");
function seeIfNumber(val){
if(typeof val === "number" && !isNaN(val)){
return "It is a number!";
}
}
ES2015
function seeIfNumber(val){
if(Number.isFinite(val)){
return "It is a number!";
}
}
Exercise: ES2015 Methods
Write a function called copyObject, which accepts one parameter, an object. The function should return a shallow copy of the object.
var o = {name: 'Elie'}
var o2 = copyObject({}, o)
o2.name = "Tim"
o2.name // 'Tim'
o.name // 'Elie'
function copyObject(obj){
return Object.assign({}, obj);
}
Write a function called checkIfFinite which accepts one parameter and returns true if that parameter is a finite number.
checkIfFinite(4) // true
checkIfFinite(-3) // true
checkIfFinite(4. // .toEqual(true
checkIfFinite(NaN) // false
checkIfFinite(Infinity) // false
function checkIfFinite(num){
return Number.isFinite(num);
}
Write a function called areAllNumbersFinite which accepts an array and returns true if every single value in the array is a finite number, otherwise return false.
var finiteNums = [4,-3,2.2]
var finiteNumsExceptOne = [4,-3,2.2,NaN]
areAllNumbersFinite(finiteNums) // true
areAllNumbersFinite(finiteNumsExceptOne) // false
function areAllNumbersFinite(arr){
return arr.every(Number.isFinite);
}
Write a function called convertArrayLikeObject which accepts a single parameter, an array like object. The function should return the array like object converted to an array.
var divs = document.getElementsByTagName('div')
divs.reduce // undefined
var converted = convertArrayLikeObject(divs)
converted.reduce // funciton(){}...
function convertArrayLikeObject(obj){
return Array.from(obj);
}
Write a function called displayEvenArguments which accepts a variable number of arguments and returns a new array with all of the arguments that are even numbers.
displayEvenArguments(1,2,3,4,5,6) // [2,4,6]
displayEvenArguments(7,8,9) // [8]
displayEvenArguments(1,3,7) // []
function displayEvenArguments(){
return Array.from(arguments).filter(val => val %2 === 0);
}
Alternative
function displayEvenArguments(...args){
return args.filter(val => val %2 === 0);
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator