Week 25 Homework 💻 🦗
New stuff we learned this week: 🤔
Javascript: Array.reduce()
- Array.reduce() takes a function that operates on each item of an array, accumulating a single value (or, you could say reducing the array to a single value). The accumulator function receives the accumulated value as its first argument, and the next item as it’s second argument:
[2, 2, 3].reduce(addItems, 0); // returns 7
function addItems(accumulation, nextItem) {
return accumulation + nextItem;
}
- the second argument passed to
Array.reduce()
is the initial value of the reduction:
let initialValue = "MY GIRLS: ";
["Harriet", "Dale"].reduce(makeSingleLine, initialValue);
// returns `MY GIRLS: Harriet Dale
function makeSingleLine(accumulation, item) {
return accumulation + " " + item;
}
Javascript: Primitive Types and Argument Passing
- in Javascript, there are 7 so-called “primitive” types. You already know about 5 of them, and we’ll save the last two for later, they are much less rarely encountered. The basic primitive types are:
string
number
boolean
null
undefined
- everything else is not a primitive type, including:
functions
objects
arrays
- etc…
- primitive types are passed to functions BY VALUE which means the function gets a COPY of the value:
let age = 41;
function subtract20(num) {
num = num - 20;
}
subtract20(age);
// `age` is STILL `41` because
// primitive types are PASSED BY VALUE
// that is to say, COPIED
- non-primitives are passed to functions BY REFERENCE which means the function gets a reference to the ACTUAL value, NOT a copy:
let jared = { age: 41 };
function setAge10(obj) {
obj.age = 10;
}
setAge10(jared);
// `jared.age` is now `10` because the
// `setAge10` function got passed a REFERENCE
// to the actual `jared` object, NOT a copy
Javascript: Code Sharing (web)
- when Brendan Eich invented Javascript, he didn’t create a built-in way to share code easily, and that missing feature is only just now being fully remedied, many years later.
- in the browser, a simple workaround/hack that was used for years (and still is used) is to share code by using a variable in the top-most scope — this is called a global variable
- in the browser, variables in the global scope are also properties of a magic variable called
window
- in order to avoid “polluting the global scope”, it was common to add a single variable which is an object, and attach things to that, like this:
// explicitly set up a global variable to hold goodies
window.JARED = {};
// add some goodies
window.JARED.greet = function(name) {
alert("Hello there " + name + "!");
};
window.JARED.addNode = function(tag, html) {
let node = document.createElement(tag);
node.innerHTML = html;
return node;
};
window.JARED.boys = ["Win", "Huck"];
- with a little bit of care, you can now load helpers and functions from multiple javascript files:
<head>
<script src="./lib-dom.js"></script>
<script src="./lib-string.js"></script>
<script src="./lib-array.js"></script>
</head>
- you just probably want to make sure that you don’t accidentally overwrite the global variable, so each of the above
lib-*
files might have a bit of code like this at the top:
if (window.SHARED === undefined) {
window.SHARED = {}:
}
// then go on adding goodies
window.SHARED.goatbanjo = 'rodeo';
Javascript: Code Sharing (node)
- when Ryan Dahl invented nodejs, he wanted to make it easy to share and re-use code, which was not easy to do in the browser. So he, and the early contributors to nodejs came up with a convention for code sharing called commonjs. It looks like this:
let coolModule = require("./cool-module");
coolModule.doCoolThing();
commonjs
works because behind the scenes, every node javascript file is wrapped in a function and then invoked, and the function is passed 5 special variables:exports
(an object that lets you “export” out stuff form your module)require
(a fancy function node gives you for pulling in other code)module
(a helpful bag of info about the “module”, including a propertyexports
which is a reference toexports
)__filename
— a string with the full path to the file__dirname
— a string with the full path of the file’s directory
- so, if you made the following node script (called
hello.js
):
console.log("Hello World!");
- what actually happens behind the scene is something like this:
// first, node WRAPS your file in a function with 5 params:
function hello(exports, require, module, __filename, __dirname) {
console.log("Hello World!");
}
// then it calls it with 5 arguments
hello({}, require, module, "/home/hello.js", "/home");
- NOTE: from now on a rocket ship 🚀 in a js code sample means “take notice, we’re talking about code now in a different file!
__filename
and__dirname
are fun and hande, but the most powerful and important parts are theexports
(most often accessed off of themodule
object asmodule.exports
) andrequire
parameters, this is what allows you to share code between files in node, like this:
// file1 - lib.js
function add17(num) {
return num + 17;
}
module.exports = add17;
// 🚀 then, in file2 - math.js
let add17 = require("./lib");
console.log(add17(5)); // logs out `23`
- the
require
function passed to each node file takes a “string” argument which is a relative path to a file you want to use. You do NOT supply the file extension, node adds it for you:
// no file extensions because Ryan Dahl was being "cute"
let module1 = require("./path/to/module1");
let module2 = require("./module2");
let banjo = require("./rodeo");
- you can set
module.exports
to whatever you want, often it is set to be a single function (like in theadd17
example above), but another very common practice, is to make it an object, so you can export multiple things from one file like this:
// in `math.js`
let halve = function(num) {
return num / 2;
};
let double = function(num) {
return num * 2;
};
// 😎 Cool Mom! I exported TWO functions!
module.exports = {
halve: halve,
double: double,
};
// 🚀 ...later on, in `do-stuff.js`...
let math = require("./math");
math.halve(22); // > 11
math.double(7); // > 14
Useful Links:
Homework Plan:
- 1 day adding to and reviewing all flash cards
- 1 day Argument Passing review & “test”
- 2 days Node Homework
- 1 day Web Homework
- 2 days touch typing practice
- 1 day watch CCCS #23
Homework day 1
- flashcard assignment
- Node Homework #1
- touch typing practice
Homework day 2
- Argument Passing Review & Test
- Web Homework #1
- watch CCCS #23
Homework day 3
- Node Homework #2
- touch typing practice
Flashcard Assignment
- add 4 new
javascript
flashcards:Array.reduce(fn, initialValue)
— make sure the back includes a description of what arguments get passed to the function, and whatinitialValue
is- “Primitive Types” (the back should contain a list of 5 types, and say that they are passed by value to functions)
- “Pass by Value”
- “Pass by Reference”
- add 5 new
nodejs
flashcards:- “commonjs”
module.exports
require
__filename
__dirname
- carefully review all of your flashcards, repeating any that you get wrong!
Argument Passing Review & Test
- carefully and slowly review the “Primitive Types and Argument Passing” section of “New Stuff” above ^^.
ssh
into your home dir- copy the file
/arg-pass-test.js
into your home dir, and edit with vim - follow the instructions — any that you get wrong, study till you figure out why it was wrong, or Slack if you can’t figure it out.
Node Homework #1
- NO
for
loops at all in this weeks homework! - slowly and carefully review the “Array.reduce()” and “Code Sharing (node)” sections of the “New Stuff” above
- Hint: parts of these problems might be good to use RunJS for, faking out
process.argv
and then finalizing it as a node script when you’ve got it working 👍 ssh
into your home dir, then make and move into a~/node/week25
dir- make a little math helper library in a file called
math.js
— it should export an object with TWO functions — one that takes two numbers and adds them together, and one that takes a single number and squares it (multiplies it by itself); - next, make another helper library module called
convert.js
— it should export an object with two functions, one which converts strings to numbers, and one which converts numbers to strings - next, make a simple node script called
sum.js
that takes any number of numeric arguments from the shell, and adds them together — it must:- import and use 2 of the four functions you created in steps 5 and 6
- use both
Array.map
andArray.reduce
- When it’s working, it should function like this:
$ node sum.js 1 1 3
> 5
$ node sum.js 5 10 100 1
> 116
- make a script called
sum-squares.js
that is similar to the previous script, but it squares all of the numbers before adding them together. It must:- import and use THREE of the four functions you created in steps 4 and 5
- use both
Array.map
twice andArray.reduce
once
- when it’s working, it should function like this:
$ node sum-squares.js 1 2 3
> 14
$ node sum-squares.js 5 6
> 61
- Extra Credit: ✨ revise the above script so that it pitches out non-numeric arguments without erroring, so that
node sum-squares.js 1 2 lol 3
still produces14
- make a script called
count-goats.js
that takes any number of string arguments from the shell, and console.logs out the number of timesgoat
occurs — it should work like this (the counting must take place by means ofArray.reduce()
):
$ node count-goats.js foo goat bar goat goat banjo
> 3
$ node count-goats.js foo bar baz
> 0
$ node count-goats.js goat banjo rodeo
> 1
Extra Credit: ✨ revise the
count-goats.js
file so that it is not case senstitive,GOAT
andgOAt
andgoat
should all be countedmake a script called
unique.js
that removes duplicates from the list of arguments provided, and logs out a nice summary of the unique items. It must:- use Array.reduce() to reduce the array to one containing no duplicates
- print the number of unique items, plus the items on a single line separated by commas (as shown below)
when it’s working correctly, it should look like this:
$ node unique.js Win Huck Huck Dale
> 3 unique items: Win, Huck, Dale
$ node unique.js Michigan Ohio Ohio Utah Ohio Utah Florida
> 4 unique items: Michigan, Ohio, Utah, Florida
- Kiah Credit: ✨ - make a script called
tally.js
that counts all the occurrences of strings in the argument list and prints them out nicely, it must use Array.reduce for the main work, plus other good stuff to format it correctly. When working, it should look like this:
$ node tally.js foo foo bar baz baz baz
> Totals: foo (2), bar (1), baz (3)
Web Homework
- slowly and carefully review the “Javascript: code sharing (web)” section of “New Stuff”.
ssh
into your home dir, then make and move into a dir:~/www/week25/
- make a webpage called
share.html
that meets the following criteria (read ALL of these before starting):- it should have an empty list, and a button with the text “add item”
- when the button is clicked, the user should be prompted for some text (using
prompt
) and whatever they type in should be added as a new list item in the (previously empty) list - the webpage should have an H1 with the text “change bg color” which, when clicked, changes the backgound color of the web page
- the webpage should load THREE javascript files, one called
add-item.js
, one calledchange-bg.js
, and the third calleddo-stuff.js
- the
do-stuff.js
file has already been created for you — copy it down from/do-stuff.js
into your current folder (you’ll also want to look at it to see how to finish the task, but you may not modify it) - the two js files that you have to create from scratch should each create and share a single function, on the
SHARED
global variable such that the code indo-stuff.js
works to fulfill the other requirements above - the two files you create should use the safety precaution shown at the very end of the “new stuff” section on web code sharing
- Extra Credit: ✨ in the
change-bg.js
file use an array and array methods to make it so you can click theh1
10 times, and get a different bg color each time - Extra Credit: ✨ use the power of scope to make it so that adding a list item prepends a number to each new list item, and the number goes up by one each time a user adds an item
Node Homework #2
ssh
into your home dir, andcd
back down into~/node/week25
- make your own helper module called
string.js
that exports X functions:- a function that changes a string to uppercase
- a function that adds 3 exclamation points to a string
- a function that replaces all of the lowercase
o
chars in a string with the char@
- a function that filters out the word
goat
- next, create a script called
yell-args.js
that takes any number of string arguments and:- removes the any that are just
goat
- uppercases them and adds 3 exclamation marks
- it should use 3 of the functions you made from
string.js
, importing them withrequire
- removes the any that are just
- when done, it should work like this:
$ node yell-args.js tofu goat rodeo sandwich
> TOFU!!!
> RODEO!!!
> SANDWICH!!!
- create a script called
weird-args.js
that works similar to the other one, except replaceso
with@
using the exported function you made, and it should not uppercase, and it should format them onto one line, like this:
$ node weird-args.js tofu goat rodeo sandwich
> t@fu!!! r@deo!!! sandwich!!!
- Extra Credit: ✨ EVERYTHING PAST THIS POINT IS EXTRA CREDIT ✨
- add a function to
string.js
that works like the function that adds 3 exclamation marks, except that it is a function maker (a function that returns a function) which leverages closure to create a function that adds 3 of any character. So if the function was calledmakeAppend3
you could use it likesomeArray.map(makeAppend3('*'))
. Use your new function to changeweird-args.js
so that the FIRST argument pass becomes what is added three times, like this:
$ node weird-args.js % tofu goat rodeo sandwich
> t@fu%%% r@deo%%% sandwich%%%
node weird-args.js * tofu goat rodeo sandwich
> t@fu*** r@deo*** sandwich***
- create a script called
find-by-sibling.js
that works like this:- it should
require
a file I created in the root dir, called/htc-members.js
(console.log out what it exports, to help figure out what it is) - it should use array methods (NO LOOPS!) to find all of the students that have a sibling named whatever is passed in as a command line arg
- it should
- if done correctly it should work like this:
$ node find-by-sibling.js Charlie
> Found 1 -- Name: Tabitha Artinian
$ node find-by-sibling.js Huck
> Found 2 -- Name: Win Henderson, Name: Harriet Henderson
- Kiah Credit: ✨ make a module called
print-found.js
that exports a single function — the function should a single argument, which is a function for selecting from HTC members. The function passed as an argument should be used in place of the whatever you used inArray.filter()
for thefind-by-sibling.js
task, and the function should take care of the rest of the work thatfind-by-sibling.js
did. Once you make this sweet function, use it to drastically simplify the code offind-by-sibling.js
and then make three more scripts (they should be dead simple to make once the function exists):- one called
find-by-parent.js
that works the same asfind-by-sibling.js
except you pass it a parent name - one called
find-teacher.js
that takes no arguments, but printsFound 1 -- Name: Jared Henderson
- one called
find-students.js
that takes no arguments, but prints out a similar list of all students - again, the 3 new scripts should be dumb simple if you construct the helper module correctly 👍
- in case that’s all not clear, if I had your module I could use it to make a script that found all of the people whose first name was
Jared
and the code would only be this:
- one called
let printFound = require("./print-found");
function findJared(member) {
return member.name === "Jared";
}
printFound(findJared);
// logs out: > Found 1 -- Name: Jared Henderson