Answers to Problem Sets from JS Hard Parts

Here is a review of the exercises and some of the concepts taught in the course JS: The Hard Parts on frontend masters. The questions were created by someone at Codesmith, and the answers are ones that I wrote. The originals are on the web here, at csbin.io

Asynchronous functions, higher order functions

The solutions on GitHub

What are asynchronous functions? In Javascript, you have an asyncronous function when you invoke a function that makes a call to code that is defined outside of the current execution context. Before explaing any further, let's take a look at an example

function makeAnAsyncCall(message) {
setTimeout(() => {
console.log(message);
}, 10000);
}

makeAnAsyncCall("This message is going to be logged out to the console in ten seconds, after all the code in the current execution context runs (even if it's more than ten seconds of code)");

// ten+ seconds of syncronous code

makeAnAsyncCall is calling a function setTimeout which is built into the JS environment. It's provided by the browser, or node. setTimeout is passed a function, and the integer 10000. Immediately upon setTimeout being called, the function passed into setTimeout is added to a queue that is being maintained in the JS engine. The integer 10000 that is passed into setTimeout is the amount of time the

This is what we mean by asynchronous functions, but higher order functions are something different. Higher order functions are when our functions are defined to either take in other function definitions by argumement, or return function definitions from the function's execution.

function addByTwo(a) { return a + 2}
function higherOrder(v, fx) { return fx(v); }
higherOrder(2, addByTwo);

or:

function a() {
let counter = 0;
return function() {
counter++;
console.log(counter);
}
}
const counter a();
counter();
counter();
counter();

Key examples: Debounce

function debounce(callback, interval) {
let timer,
readyToCall = true;

/**
*
* @returns callback(), or "undefined" depending on if interval ms have ellapsed since last call to debouncedFunction
*/

function debouncedFunction() {
if (readyToCall) {
readyToCall = false;

timer = setTimeout(() => {
readyToCall = true;
}, interval);

return callback();
} else {
// when debouncedFunction is not ready to be called,the timer running from the previous call should be reset—making it "debouced three seconds from every call", instead of "debounded three seconds from every successful call"
clearTimeout(timer);

timer = setTimeout(() => {
readyToCall = true;
}, interval);

return "unsucessful";
}
}

return debouncedFunction;
}

function sayHi() {
return "hi";
}

const debouncedSayHi = debounce(sayHi, 3000);

/* tests */

console.log(debouncedSayHi()); // -> 'hi'

setTimeout(() => {
console.log(debouncedSayHi());
}, 2000); // -> undefined

setTimeout(() => {
console.log(debouncedSayHi());
}, 4000); // -> undefined

setTimeout(() => {
console.log(debouncedSayHi());
}, 8000); // -> 'hi'

// ?? using iterm to run file, there is a second pause in between when cb for last setTimeout? I would expect it to just cut out right there

Key example: Seconds Clock

class SecondClock {
constructor(cb) {
this.cb = cb;
this.secondsHand = 0;
this.clock = undefined;
}
start() {
this.clock = setInterval(() => {
this.cb(++this.secondsHand);
}, 1000);
}
reset() {
clearInterval(this.clock);
}
}

//tests

const clock = new SecondClock((val) => {
console.log(val);
});

console.log("Started Clock.");
clock.start();

setTimeout(() => {
clock.reset();
console.log("Stopped Clock after 6 seconds.");
}, 6000);

Scope & Closure

The solutions on GitHub

Key examples: Blackjack

function blackjack(array) {
function dealer(a, b) {
let callCount = 0;
let cardCount = a + b;

function player() {
callCount++;

if (cardCount > 21) {
return "You are donezo!";
}

if (callCount === 1) {
return cardCount;
} else {
cardCount += array.shift();
if (cardCount > 21) {
return "Bust!";
} else {
return cardCount;
}
}
}
return player;
}
return dealer;
}

/*** DEALER ***/
const deal = blackjack([
2, 6, 1, 7, 11, 4, 6, 3, 9, 8, 9, 3, 10, 4, 5, 3, 7, 4, 9, 6, 10, 11,
]);

/*** PLAYER 1 ***/
const i_like_to_live_dangerously = deal(4, 5);
console.log(i_like_to_live_dangerously()); // => should log 9
console.log(i_like_to_live_dangerously()); // => should log 11
console.log(i_like_to_live_dangerously()); // => should log 17
console.log(i_like_to_live_dangerously()); // => should log 18
console.log(i_like_to_live_dangerously()); // => should log 'bust'
console.log(i_like_to_live_dangerously()); // => should log 'you are done!'
console.log(i_like_to_live_dangerously()); // => should log 'you are done!'

Key examples: Execution history

function makeHistory(limit) {
const storage = [];
// let counter = 0;
function processString(str) {
if (storage.length > limit) {
storage.shift();
}

if (str === "undo") {
if (storage.length === 0) {
return "Nothing to undo!";
}
console.log(storage);

let poppedEl = storage.pop();

console.log(storage);
return `${poppedEl} undone`;
} else {
storage.push(str);
return `${str} done`;
}
}

return processString;
}

// /*** Uncomment these to check your work! ***/
const myActions = makeHistory(2);
console.log(myActions("jump")); // => should log 'jump done'
console.log(myActions("undo")); // => should log 'jump undone'
console.log(myActions("walk")); // => should log 'walk done'
console.log(myActions("code")); // => should log 'code done'
console.log(myActions("pose")); // => should log 'pose done'
console.log(myActions("undo")); // => should log 'pose undone'
console.log(myActions("undo")); // => should log 'code undone'
console.log(myActions("undo")); // => should log 'nothing to undo'

Promises & Async

The solutions on GitHub

Key examples: using an API though promises:

const fakePeople = [
{ name: "Rudolph", hasPets: false, currentTemp: 98.6 },
{ name: "Zebulon", hasPets: true, currentTemp: 22.6 },
{ name: "Harold", hasPets: true, currentTemp: 98.3 },
];

const fakeAPICall = (i) => {
const returnTime = Math.floor(Math.random() * 1000);
return new Promise((resolve, reject) => {
if (i >= 0 && i < fakePeople.length) {
setTimeout(() => resolve(fakePeople[i]), returnTime);
} else {
reject({ message: "index out of range" });
}
});
};

const getAllData = () => {
fakeAPICall(0).then((res) => console.log(res));
fakeAPICall(1).then((res) => console.log(res));
fakeAPICall(2).then((res) => console.log(res));
};

getAllData();

Objects & Object Oriented Programming

The solutions on GitHub

Key examples: Using classes to create new objects and change their prototype chain:

class PersonClass {
constructor(name) {
this.name = name;
}

greet() {
console.log("hello");
}
}

// /********* Uncomment this line to test your work! *********/
const george = new PersonClass();
george.greet(); // -> Logs 'hello'

/*** CHALLENGE 9 ***/

// add code here

class DeveloperClass extends PersonClass {
introduce() {
console.log(`Hi! My name is ${this.name}`);
}
}

// /********* Uncomment these lines to test your work! *********/
const thai = new DeveloperClass("Thai", 32);
console.log(thai.name); // -> Logs 'Thai'
thai.introduce(); //-> Logs 'Hello World, my name is Thai'

Key examples: creating new object types using constructor functions, and create them using the new keyword:

function PersonConstructor() {
this.greet = function () {
console.log("hello");
};
this.introduce = function () {
console.log("Hi, my name is " + this.name);
};
}

// /********* Uncomment this line to test your work! *********/
const simon = new PersonConstructor();
simon.greet(); // -> Logs 'hello'

/*** CHALLENGE 6 ***/

function personFromConstructor(name, age) {
const person = new PersonConstructor();
person.name = name;
person.age = age;
return person;
}

const mike = personFromConstructor("Mike", 30);

// /********* Uncomment these lines to test your work! *********/
console.log(mike.name); // -> Logs 'Mike'
console.log(mike.age); //-> Logs 30
mike.greet(); //-> Logs 'hello'