Let's build our own iterator methods!
- Fork & Clone this repo.
- Plan Ahead: Research each iterator before you write any code.
- Check Your Solution: Write Test Driver Code, or run the included Tests (see below).
- Make a Commit for every task you complete.
For the following tasks, it is essential that you understand the specific built-in array method. See MDN Array Reference
Before you start each task, ask yourself questions such as:
- What are our inputs?
- What is our output?
- What happens on each iteration?
- What does the callback function do?
- What gets passed into our callback function? That is, what are its inputs/parameters?
- Where does the callback function come from?
You should be able to answer most of these questions based on the documentation you just read or by experimenting in the browser developer tools.
- Write out pseudo-code before syntactically correct code.
- Write down inputs that you'll use to test the function, and write what the output should be (you can use the examples).
- Still on paper, on a whiteboard, or in comments, walk through what your function will do when called on the test input.
- Only when you have pseudo-code, test input, and expected output should you write syntactically correct code to implement the body of the function.
- Once you're confident in your syntax, test again.
- Create a function
myFind
which implementsArray.prototype.find
.myFind
takes in an array and a callback function.myFind
should iterate through all elements in the array and call the callback function with these parameters: the current element, the current index, and the array itself. If the callback returnstrue
for an element,myFind
should immediately return the value of the element. If the callback never returns true for an element,myFind
should returnundefined
. Seefind
. Work instarter-code/myFind.js
function myFind (array, callback) {
// your code here!
// myFind should duplicate the behavior of find
}
click for example...
Example inputs that your `myFind` function could take:var words = ['air', 'tree', 'sunshine', 'trail', 'fire'];
function isLong(element, index, arr){
return element.length > 4;
}
Example of calling your myFind
function on the inputs above:
myFind(words, isLong);
// returns "sunshine"
// note, this should be the same as calling
words.find(isLong);
- Create a function
myEach
which implementsArray.prototype.forEach
.myEach
should take in an array and a callback function.myEach
should iterate through all elements in the array and call the callback function with these parameters: the current element, the current index, and the array itself.myEach
should returnundefined
. SeeforEach
. Work in thestarter-code/myEach.js
file.
function myEach (array, callback) {
// your code here!
// myEach should duplicate the behavior of forEach
}
click for example...
Example Inputs:var words = ['apple', 'banana', 'cherry'];
function logAsList(element, index, arr){
console.log(index + '. ' + element);
}
Example Use:
myEach(words, logAsList);
// console.logs:
// 1. apple
// 2. banana
// 3. cherry
// note, this should be the same as calling
words.forEach(logAsList);
- Create a function
myMap
which implementsArray.prototype.map
.myMap
takes in an array and a callback function.myMap
should iterate through all elements in the array and call the callback function with these parameters: the current element, the current index, and the array itself.myMap
should return a new array containing the results of the callback calls. Seemap
. Work instarter-code/myMap.js
.
function myMap (array, callback) {
// your code here!
// myMap should duplicate the behavior of map
}
click for example...
Example Inputs:var numbers = [1, 4, 9];
function timesTwo(element, index, arr){
return element*2;
}
Example Use:
var result = myMap(numbers, timesTwo);
// result is [2, 8, 18]; numbers is still [1, 4, 9]
// note, this should be the same as saying:
result = numbers.map(timesTwo);
- Create a function
myFilter
which implementsArray.prototype.filter
.myFilter
takes in an array and a callback function. The callback function will have the following parameters: the current element, the current index, and the array itself. The callback function will returntrue
orfalse
.myFilter
should return a new array containing all the elements for which the callback function returnedtrue
. Seefilter
. Work instarter-code/myFilter.js
.
function myFilter (array, callback) {
// your code here!
// myFilter should duplicate the behavior of filter
}
click for example...
Example Inputs:var numbers = [1, 4, 9, 16];
function isEven(element, index, arr){
return element % 2 === 0;
}
Example Use:
var result = myFilter(numbers, isEven);
// newArr is [4, 16]; numbers is still [1, 4, 9, 16]
// note, this should be the same as saying:
result = numbers.filter(isEven);
- Create a function
myReduce
which implementsArray.prototype.reduce
.myReduce
takes in an array and a callback function, and it can optionally take a starting value. It should iterate through all elements in the array and call the callback function with these parameters: the previous value (or starting value if no previous yet), the current element, the current index, and the array itself.myReduce
should return a single value built up from the previous values. Seereduce
. Work instarter-code/myReduce.js
.
function myReduce(array, callback, initialValue) {
// your code here!
// myReduce should duplicate the behavior of reduce
}
click for example...
Example Inputs:var numbers = [1, 4, 9];
function addUp(previous, element, index, arr){
return previous + element;
}
Example Use:
var result = myReduce(numbers, addUp, 2);
// result is 16
// note, this should be the same as saying:
result = numbers.reduce(addUp, 2);
Pro-Tip: It's easier to build incrementally than to try to do everything all at once. Remember to start as simple as possible and add features as you go.
To check your code manually, we recommend you write "test driver code" inside of index.js
instead of from inside your iterator files (e.g. myEach.js
, myMap.js
, myReduce.js
). This helps keep your "test driver code" separate from your "implementation code".
Here's an example of what good test driver code looks like:
//index.js
var input = ["a","b","c"];
var output = myMap(input, function capitalize(v){
return v.toUpperCase();
});
console.log('Testing myMap')
console.log("Expected:", ["A", "B", "C"], "Got:", output)
To execute this code from the command-line, you need to type:
# make sure you are inside the building-js-iterators-lab directory
node index.js
Note: Even though
myMap
lives in a different file, we still have access to it inindex.js
. That's whatrequire
is doing in each of the first few lines.
For each task (tasks.forEach
!), you can run the provided tests to check your work and confirm your solution.
Make sure you are inside the building-js-iterators-lab
directory.
From the command-line, run:
# make sure you are inside the building-js-iterators-lab directory
npm install
npm install -g mocha
To run the tests for myMap
from the command-line, type:
# make sure you are inside the building-js-iterators-lab directory
mocha spec/myMapSpec.js
This will test the myMap
function you wrote in myMap.js
.
You can do the same thing for the other iterators as well:
# make sure you are inside the building-js-iterators-lab directory
mocha spec/myEachSpec.js
mocha spec/myReduceSpec.js
Pro-Tip: Let the tests call your function for you. You should not be calling, e.g.
myMap
in your code directly.
GREEN (✓) - test has passed. Nice work! RED - test has failed. Keep working!
For example, here is some test output with three passing (✓) tests:
$ mocha spec/myMapSpec.js
myMap
1) takes and calls a callback function
results: []
2) passes each item in the array to the callback
results: []
3) passes each index in the array to the callback
✓ passes the entire array to the callback
results: undefined
4) returns an array
results: undefined
5) returns an array with the same number of elements
results: undefined
6) returns an array constructed from the return values of the callback
results: [ 'a', 'b', 'c', 'd' ]
✓ doesn't alter the original array
results: []
✓ works with arrays of length 0
results: []
7) works with arrays of length 1
Note: Sometimes tests pass right away. This is called a "false positive". As you start writing code, some of your prematurely "green" tests will turn "red"!
Example - Failure Message 7
Here's an example of a failure messages (pay close attention to these, they give you hints!):
7) myMap works with arrays of length 1:
AssertionError: expected 0 to equal 1
+ expected - actual
+1
-0
at Context.testArrayL1 (spec/myMapSpec.js:126:38)
An assertion is a statement that asserts or says this "MUST BE TRUE". If the statement turns out to be false, then the assertion fails and the test fails.
In the above output we can see that the assertion in spec/myMapSpec.js:126:38
(at line 126, and at character 38) expected 0
(the "actual" result) to equal 1
(the "expected" result).
This is a little unclear, but at least it tells us exactly what part of the file to look at.
Example - Failure Message 2
2) myMap passes each item in the array to the callback:
AssertionError: expected [] to have the same members as [ 'a', 'b', 'c', 'd' ]
at Context.testEachItem (spec/myMapSpec.js:37:36)
What do you think this means?
click for explanation
At line 37 in the test file, there was an expectation that an array would have the elements `['a', 'b', 'c', 'd']`. Instead, it got an empty array!When you're finished for the day, edit this README to include your name, a link to the original repository, and a 3-5 sentence reflection on completing this training at the top of the readme. Push your updates to GitHub!