@@ -36,8 +36,7 @@ <h3 class="">Javascript function programming koans</h3>
36
36
37
37
< div id ="area ">
38
38
< pre id ="pre " class ="javascript " style ="height: 425px; ">
39
- < a href ="#1 "> 1) Our Goal</ a >
40
-
39
+ /* TOC goes here */
41
40
</ pre >
42
41
< form id ="form ">
43
42
< div class ="buttons " style ="display: none; ">
@@ -92,8 +91,8 @@ <h3 class="">Javascript function programming koans</h3>
92
91
*/
93
92
</ pre > </ dd >
94
93
95
- <!-- Slide 3 -->
96
- < dt > How koans work (2) </ dt >
94
+ <!-- Slide 4 -->
95
+ < dt > More on how koans work... </ dt >
97
96
< dd > < pre >
98
97
//Sometimes we just want to see what's going on
99
98
var theAnswer = 6 * 7;
@@ -107,7 +106,7 @@ <h3 class="">Javascript function programming koans</h3>
107
106
}
108
107
</ pre > </ dd >
109
108
110
- <!-- Slide 1 -->
109
+ <!-- Slide 5 -->
111
110
< dt > First class functions</ dt >
112
111
< dd > </ dd >
113
112
@@ -128,7 +127,7 @@ <h3 class="">Javascript function programming koans</h3>
128
127
*/
129
128
</ pre > </ dd >
130
129
131
- <!-- Slide 5 -->
130
+ <!-- Slide 6 -->
132
131
< dt > Giving functions names</ dt >
133
132
< dd > < pre >
134
133
var add = function(x, y) {
@@ -143,7 +142,7 @@ <h3 class="">Javascript function programming koans</h3>
143
142
assert(alsoAdd(1, 6) === FILL_ME_IN, "Named functions behave just like other variables");
144
143
</ pre > </ dd >
145
144
146
- <!-- Slide 6 -->
145
+ <!-- Slide 7 -->
147
146
< dt > Storing functions in data structures</ dt >
148
147
< dd > < pre >
149
148
var result = 0;
@@ -166,7 +165,7 @@ <h3 class="">Javascript function programming koans</h3>
166
165
assert(result === FILL_ME_IN, "what is the final result?");
167
166
</ pre > </ dd >
168
167
169
- <!-- Slide 7 -->
168
+ <!-- Slide 8 -->
170
169
< dt > Passing a function as an argument to another function call</ dt >
171
170
< dd > < pre >
172
171
var afterMeditation = function(knowledge) {
@@ -181,7 +180,7 @@ <h3 class="">Javascript function programming koans</h3>
181
180
thinkLongAndHard('wind', 'rain', afterMeditation);
182
181
</ pre > </ dd >
183
182
184
- <!-- Slide 8 -->
183
+ <!-- Slide 9 -->
185
184
< dt > You can return a function from another function</ dt >
186
185
< dd > < pre >
187
186
var powerFactory = function(power) {
@@ -200,11 +199,11 @@ <h3 class="">Javascript function programming koans</h3>
200
199
assert(squared(2) + cubed(3) === FILL_ME_IN, "functions can create new functions");
201
200
</ pre > </ dd >
202
201
203
- <!-- Slide 1 -->
202
+ <!-- Slide 10 -->
204
203
< dt > Higher order functions</ dt >
205
204
< dd > </ dd >
206
205
207
- <!-- Slide 9 -->
206
+ <!-- Slide 11 -->
208
207
< dt > First class functions make common operations with collections easy</ dt >
209
208
< dd > < pre >
210
209
/*
@@ -219,15 +218,18 @@ <h3 class="">Javascript function programming koans</h3>
219
218
* (7) range
220
219
* (8) flatten
221
220
*
222
- * because the apply a function to a list in a common way.
221
+ * because they apply a function to a list in a common way.
222
+ * (We use the underscore.js library to ensure these are
223
+ * applied consistently across all browsers)
223
224
*
224
225
*/
225
226
</ pre > </ dd >
226
227
227
- <!-- Slide 10 -->
228
+ <!-- Slide 12 -->
228
229
< dt > Each</ dt >
229
230
< dd > < pre >
230
231
/* Iterates over a list of elements, yielding each in turn to an iterator function. */
232
+
231
233
var numbers = [1,2,3];
232
234
var msg = "";
233
235
var isEven = function(item) {
@@ -240,11 +242,172 @@ <h3 class="">Javascript function programming koans</h3>
240
242
assert(numbers === FILL_ME_IN, "but the original list wasn't touched");
241
243
</ pre > </ dd >
242
244
245
+ <!-- Slide 13 -->
246
+ < dt > Map</ dt >
247
+ < dd > < pre >
248
+ /* Produces a new array of values by mapping each value in list through a transformation function (iterator). */
243
249
244
- <!-- Slide 9 -->
250
+ var numbers = [1, 2, 3];
251
+ var numbersPlus1 = _.map(numbers, function(x) { return x + 1 });
252
+
253
+ assert(numbersPlus1 === FILL_ME_IN, "each element is the result of the function applied to the original list");
254
+ assert(numbers === FILL_ME_IN, "but the original list wasn't touched");
255
+ </ pre > </ dd >
256
+
257
+ <!-- Slide 14 -->
258
+ < dt > Filter</ dt >
259
+ < dd > < pre >
260
+ /* Looks through each value in the list, returning an array of all the values that pass a truth test (iterator) */
261
+
262
+ var numbers = [1,2,3];
263
+ var odd = _(numbers).filter(function (x) { return x % 2 !== 0 });
264
+
265
+ assert(odd === FILL_ME_IN, "should only contain odd");
266
+ assert(numbers === FILL_ME_IN, "but the original list isn't touched");
267
+ </ pre > </ dd >
268
+
269
+ <!-- Slide 15 -->
270
+ < dt > Reduce</ dt >
271
+ < dd > < pre >
272
+ /* Reduce boils down a list of values into a single value. */
273
+
274
+ var numbers = [1, 2, 3];
275
+ var reduction = _(numbers).reduce(
276
+ function(/* result from last call */ memo, /* current */ x) { return memo + x }, /* initial */ 0);
277
+
278
+ assert(reduction === FILL_ME_IN, "should be the cumulative sum");
279
+ assert(numbers === FILL_ME_IN, "but the original list isn't touched");
280
+ </ pre > </ dd >
281
+
282
+ <!-- Slide 16 -->
283
+ < dt > All</ dt >
284
+ < dd > < pre >
285
+ /* Returns true if all of the values in the list pass the iterator truth test */
286
+
287
+ var onlyEven = [2,4,6];
288
+ var mixedBag = [2,4,5,6];
289
+
290
+ var isEven = function(x) { return x % 2 === 0 };
291
+
292
+ assert(_(onlyEven).all(isEven) === FILL_ME_IN, "are _all_ of the list items even?");
293
+ assert(_(mixedBag).all(isEven) === FILL_ME_IN, "leave the original list alone!");
294
+ </ pre > </ dd >
295
+
296
+ <!-- Slide 17 -->
297
+ < dt > Any</ dt >
298
+ < dd > < pre >
299
+ /* Returns true if any of the values in the list pass the iterator truth test.
300
+ * Short-circuits and stops traversing the list if a true element is found.
301
+ */
302
+
303
+ var onlyEven = [2,4,6];
304
+ var mixedBag = [2,4,5,6];
305
+
306
+ var isEven = function(x) { return x % 2 === 0 };
307
+
308
+ assert(_(onlyEven).any(isEven) === FILL_ME_IN, "are any of the list items even?");
309
+ assert(_(mixedBag).any(isEven) === FILL_ME_IN, "leave the original list alone!");
310
+ </ pre > </ dd >
311
+
312
+ <!-- Slide 18 -->
313
+ < dt > Range</ dt >
314
+ < dd > < pre >
315
+ /* A function to create flexibly-numbered lists of integers, handy for each and map loops. */
316
+
317
+ assert(_.range(3) === FILL_ME_IN, "should have 3 elements");
318
+ assert(_.range(1, 4) === FILL_ME_IN, "should start at 1 and end at 4 (exclusive)" );
319
+ assert(_.range(0, -4, -1) === FILL_ME_IN, "should increment in steps of -1");
320
+ </ pre > </ dd >
321
+
322
+ <!-- Slide 19 -->
323
+ < dt > Flatten</ dt >
324
+ < dd > < pre >
325
+ /* A function to create flexibly-numbered lists of integers, handy for each and map loops. */
326
+ expect(_([ [1, 2], [3, 4] ]).flatten() === FILL_ME_IN);
327
+ </ pre > </ dd >
328
+
329
+ <!-- Slide 20 -->
330
+ < dt > Chain</ dt >
331
+ < dd > < pre >
332
+ /* Returns a wrapped object.
333
+ * Calling methods on this object will continue to return wrapped objects until value is used.
334
+ */
335
+
336
+ var result = _([ [0, 1], 2 ]).chain()
337
+ .flatten()
338
+ .map(function(x) { return x+1 } )
339
+ .reduce(function (sum, x) { return sum + x })
340
+ .value();
341
+
342
+ assert(result === FILL_ME_IN);
343
+ </ pre > </ dd >
344
+
345
+
346
+ <!-- Slide 21 -->
245
347
< dt > Continuations</ dt >
348
+ < dd > </ dd >
349
+
350
+ <!-- Slide 22 -->
351
+ < dt > Continuations enable async programming</ dt >
352
+ < dd > < pre >
353
+ /*TODO: Sample involving waiting on lots of network calls -
354
+ perhaps fetching a set of RSS feeds & doing some aggregation? */
355
+ </ pre > </ dd >
356
+
357
+ <!-- Slide 23 -->
358
+ < dt > Applying our enlightenment</ dt >
359
+ < dd > </ dd >
360
+
361
+ <!-- Slide 24 -->
362
+ < dt > Applying our enlightenment</ dt >
363
+ < dd > < pre >
364
+ var products = [
365
+ { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false },
366
+ { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false },
367
+ { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false },
368
+ { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true },
369
+ { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true }
370
+ ];
371
+
372
+ /* Given I'm allergic to nuts and hate mushrooms, find a pizza I can eat (imperative) */
373
+
374
+ var i,j,hasMushrooms, productsICanEat = [];
375
+
376
+ for (i = 0; i < products .length; i+ =1) {
377
+ if (products[i].containsNuts === false) {
378
+ hasMushrooms = false;
379
+ for (j = 0; j < products [i].ingredients.length; j+ =1) {
380
+ if (products[i].ingredients[j] === "mushrooms ") {
381
+ hasMushrooms = true;
382
+ }
383
+ }
384
+ if (!hasMushrooms) productsICanEat.push(products[i]);
385
+ }
386
+ }
387
+
388
+ assert(productsICanEat.length == FILL_ME_IN);
389
+
390
+ /* now solve in a functional style */
391
+
392
+ productsICanEat = [];
393
+
394
+ /* try using filter() & all() / any() */
395
+
396
+ assert(productsICanEat.length === FILL_ME_IN);
397
+
398
+ </ pre > </ dd >
399
+
400
+ <!-- Slide 25 -->
401
+ < dt > Go forth</ dt >
246
402
< dd > < pre >
247
- /*TODO*/
403
+ /* Congratulations grasshopper, you have reached the first level of
404
+ * functional enlightenment!
405
+ *
406
+ * Remember to take this new awareness with you when solving
407
+ * everyday problems - you will find that many of your
408
+ * existing tools contain functional elements, and that these
409
+ * can greatly simplify a certain class of problems
410
+ */
248
411
</ pre > </ dd >
249
412
250
413
</ dl >
0 commit comments