-
Fork this repo to your own GitHub, and clone your copy to Cloud9
-
Move to the directory you cloned and run
npm install
from the command line -
For every exercise:
- From the command line, run:
npm test test/<nameOfTheExercise>.js
For example, for the first exercise:
npm test test/forEach.js
- Look at the failing test results
- In
workshop.js
, fill in the function code and re-run the tests - Continue doing this until all the tests have passed. Then move to the next exercise.
Make this function call the callback
once for every element in theArray
. Unlike JavaScript's Array.prototype.forEach
, the callback
function will receive only one argument: the current item.
NOTE: It's really important that you build the code of this function well, because you will re-use it throughout the workshop to create more complex functions. This practice of re-using and composing functions together to create more complex operations is one of the core principles of functional programming.
Make this function return a new array containing every element of the input array passed through the mapping function. For example:
function map(mappingFunction, theArray) {
// You write the code here
}
function multiplyByTwo(x) {
return x * 2;
}
var values = [1,10,15,16];
var doubleValues = map(multiplyByTwo, values); // [2,20,30,32]
NOTE: You can re-use your forEach
function to do this exercise ;)
Make this function return a new array containing only the elements of the input array where the predicate function returns true
or a truthy value.
NOTE: A predicate is simply a function that checks whether something is true about its input. It normally returns true
and false
only. Here's an example:
function filter(predicate, theArray) {
// You write the code here
}
function isEven(x) {
return x % 2 === 0;
}
var values = [1,10,15,16];
var evenValues = filter(isEven, values); // [10,16]
NOTE: You can re-use your forEach
function to do this exercise ;)
Make this function return:
true
if all the elements in the input array pass the predicate functionfalse
otherwise.- If passed an empty array, then return
true
.
To get the full points on this exercise, your every
function has to stop as soon as it encounters an item for which the predicate function returns false
. You don't need to go any further.
Make this function return:
true
if at least one element in the input array passes the predicate functionfalse
otherwise.- If passed an empty array, then return
false
.
To get the full points on this exercise, your some
function has to stop as soon as it encounters an item for which the predicate function returns true
. You don't need to go any further.
Make this function return the index of the first item in the input array that is ===
to the input item. If no item in the input array is ===
to the input item, then return -1
. For example:
var fruits = ['orange', 'apple', 'banana', 'apple'];
indexOf('apple', fruits); // 1
indexOf('pineapple', fruits); // -1
indexOf('anything', []); // -1
Make this function return the index of the first item in the input array for which the predicate function returns true
. Return -1
if no matching item is found. For example:
var pets = [
{id: 33, name: 'popcorn', species: 'dog'},
{id: 46, name: 'purrito', species: 'cat'},
{id: 47, name: 'bob', species: 'fish'},
{id: 49, name: 'nacho', species: 'dog'}
];
function isDog(item) {
return item.species === 'dog';
}
var firstDogIndex = findIndex(isDog, pets);
After successfully implementing the function, explain in your own words why we need findIndex
when we already have indexOf
. They're two functions that return an array index based on a condition, but there is a fundamental difference between them.
Hint: it is related to how ===
works with objects.
Make this function return the first element of the input array if it is called with one argument. If called with two arguments, then make it return an array of the first n
elements of the input array. If n
is larger than the number of elements in the input array, return the whole array. If n
is negative, return an empty array. For example:
first([4,5,6]); // 4
first(2, ['a','b','c','d']); // ['a','b']
first(1, ['a','b','c']); // ['a']
first(10, ['a','b','c']); // ['a','b','c']
Make this function return the last element of the input array if it is called with one argument. If called with two arguments, then make it return an array of the last n
elements of the input array. If n
is larger than the number of elements in the input array, return the whole array. If n
is negative, return an empty array. For example:
last([4,5,6]); // 6
last(2, ['a','b','c','d']); // ['c','d']
last(1, ['a','b','c']); // ['c']
last(10, ['a','b','c']); // ['a','b','c']
Make this function return a new array where each item is the value of the property named property
in the current object in the loop. Here a few examples are better:
var pets = [
{id: 33, owner: 'nyancat', name: 'popcorn', species: 'dog'},
{id: 46, name: 'purrito', species: 'cat'},
{id: 47, name: 'bob', species: 'fish'},
{id: 49, owner: 'nyancat', name: 'nacho', species: 'dog'}
];
pluck('id', pets); // [33,46,47,49]
pluck('name', pets); // ['popcorn','purrito','bob','nacho']
pluck('owner', pets); // ['nyancat', undefined, undefined, 'nyancat']
Make this function return a new array that "un-nests" the input array. Here are a few examples:
flatten([1,2,3]); // [1,2,3] no change
flatten([[1], [2,3], 4, 5]); // [1,2,3,4,5];
flatten([[['hello'], 'world']]); // ['hello','world'];
Make this function return a new function that will always return the opposite of the predicate function it is passed. This first version of your solution will work for one argument only. For example:
function isEven(num) {
return num % 2 === 0;
}
var isOdd = negate1(isEven); // function that returns the opposite of isEven for the same input
isEven(3); // false
isOdd(3); // true
Make this function return a new functionthat will always return the opposite of the predicate function it is passed. This version has to work with an arbitrary number of arguments. For example:
function firstDividesSecond(first, second) {
return second % first === 0;
}
var firstDoesNotDivideSecond = negate2(firstDividesSecond);
This time you won't be able to create a function that only takes one argument. To complete this exercise, you'll have to learn about two concepts:
Make this function return a new function that will take one argument and execute fun2
with it. Then, take the return value of fun2
and pass it to fun1
. Finally return the return value of fun1
. Here, an example would work best:
function compose1(fun1, fun2) {
// Your code
}
function scream(str) {
return str.toUpperCase();
}
function shout(str) {
return str + '!!!';
}
var screamAndShout = compose1(shout, scream);
screamAndShout('Hello World'); // HELLO WORLD!!!
This is the same thing as compose1
but with an arbitrary number of functions in an array. Make this function return a new function that will take one argument. You will be passing this argument to the last function in arrOfFuncs
. Take the return value and pass it to the previous function. Keep doing this all the way to the first function, and return the return value of the first function. Example:
function compose2(arrOfFuncs) {
// Your code
}
// Takes a string, returns a string
function toLowerCase(str) {
return str.toLowerCase();
}
// Takes a string, returns an array
function splitByWord(str) {
return str.split(' ');
}
// Takes an array, returns a string
function joinWithDashes(arrOfWords) {
return arrOfWords.join('-');
}
// Takes a string, returns a string by doing toLowerCase -> splitByWord -> joinWithDashes
var createSlug = compose2([joinWithDashes, splitByWord, toLowerCase]);
createSlug('The Quick Brown Fox'); // the-quick-brown-fox