9/08/2019: My Progression Towards FreecodeCamp Javascript Algorithms And Data Structures Certification: Basic Algorithm Scripting

Introduction

Today, I completed the Basic Algorithm Scripting module of the Javascript Algorithms And Data Structures Certification course on FreeCodeCamp. I converted my answers into an API that I can require(), then reference at any time. The API code is shown below.

/*
  I built this small api while working the basic algorithm scripting module
  of the Javascript Algorithms And Data Structures Certification course
  on FreeCodeCamp
*/

const libAlgorithms = 
{
  //console.log(libAlgorithms.CelsiusToFahrenheit(0));
  CelsiusToFahrenheit: function (celsius) 
  {
    return (celsius * (9 / 5)) + 32;
  },
  //console.log(libAlgorithms.ReverseString("this is a test"));
  ReverseString: function (str) 
  {
    return str.split("").reverse().join("");
  },
  // console.log(libAlgorithms.Factorial(5));
  Factorial: function(n) 
  {
    return (n != 1) ? n * libAlgorithms.Factorial(n - 1) : 1;
  },
  // console.log(libAlgorithms.LongestWord("this is an algorithm"));
  LongestWord: function (str) 
  {
    var words = str.split(' ');
    return words.reduce(function longer(champ, contender) 
    {
      return (contender.length > champ.length) ? contender : champ;
    });
  },
  // console.log(libAlgorithms.MaxNumberInNarrays([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]], 0));
  MaxOrMinNumberInNarrays: function (arr, target) 
  {
    let result = [];
    for(let item in arr)
    {
      if(target)
      {
        result.push(Math.max(...arr[item]));
      }
      else 
      {
        result.push(Math.min(...arr[item]));
      }
    }
    return result;
  },
  /*
    console.log(SumAndAverage(anarr));console.log(SumAndAverage(anarr).Sum);console.log(SumAndAverage(anarr).Average);
    let acollection = [[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]];
    for (i=0;i num ? '...' : '');
  },
  // console.log(EvensOrOdds(arr, 0));
  EvensOrOdds: function (arr, target)
  {
    const fDetect = function(num) { return num % 2 === target; };
    return arr.filter(num => fDetect(num));
  }, 
  // console.log(libAlgorithms.CapitalizeIt("mary had a little lamb"));
  CapitalizeIt: function (phrase) 
  {
    return phrase
      .toLowerCase()
      .split(' ')
      .map(word => word.charAt(0).toUpperCase() + word.slice(1))
      .join(' ');
  },
  // RemoveAllFalsies([7, "ate", "", false, 9]);
  RemoveAllFalsies: function (arr) 
  {
    return arr.filter(Boolean);
  }, 
  // console.log(libAlgorithms.GetIndexToIns([10, 20, 30, 40, 60], 50));
  GetIndexToIns: function (arr, num) 
  {
    return arr.concat(num).sort((a,b) => a-b).indexOf(num);
  }, 
  // console.log(libAlgorithms.SecondElementContainedInFirst(["hello", "hello"]));
  SecondElementContainedInFirst: function (arr) 
  {
    return arr[1].toLowerCase()
      .split('')
      .every
      (
        function(char) 
        {
          return arr[0].toLowerCase().indexOf(char) != -1;
        }
      );
  }, 
  // console.log(libAlgorithms.SplitToMultiDimensional(["a", "b", "c", "d", "e", "f"], 2));
  SplitToMultiDimensional: function (arr, size) 
  {
    if (arr.length <= size)
    {
      return [arr];
    }
    else 
    {
      return [arr.slice(0,size)].concat(libAlgorithms.SplitToMultiDimensional(arr.slice(size),size));
    }
  }

}

 

9/07/2019: My Progression Towards FreecodeCamp Javascript Algorithms And Data Structures Certification: Object Arrays (Collections)

Introduction

Today, I completed the Basic Data Structures module of the Javascript Algorithms And Data Structures Certification course on FreeCodeCamp. This stuff I have been familiar with in other languages and technologies for years, I just had to get the syntax right. Below is what I found. Now, rather than for loops, I plan to learn how to use the advanced ES6 features such as array comprehensions and iterator chaining.

/*
  You can google all over the web, and every damn example
  shows an object array like this:

  let users = 
  {
    {age: 27, online: false},
    {age: 32, online: true},
    {age: 48, online: false},
    {age: 19, online: true}
  };
  
  But....how the heck do you iterate through a collection...
  LIKE THIS:
  
  let users = 
  {
    George: {age: 27, online: false},
    Paul: {age: 32, online: true},
    John: {age: 48, online: false},
    Ringo: {age: 19, online: true}
  };
  
  Well...like this:
*/
  
let users = 
{
  George: {age: 27, online: false},
  Paul: {age: 32, online: true},
  John: {age: 48, online: false},
  Ringo: {age: 19, online: true}
};

function countOnline(obj) 
{
  let thecount = 0;
  for(let user in users)
  {
    if (obj[user].online)
    {
      thecount++;
    }
  }
  return thecount;
}

// and here's how to access members of the collection itself
let arrUserkeys = Object.keys(users);

console.log("Number of users online = " + countOnline(users));

//here's how to WRITE to a data structure like this:

let user = {
  name: 'Kenneth',
  age: 28,
  data: {
    username: 'kennethCodesAllDay',
    joinDate: 'March 26, 2016',
    organization: 'freeCodeCamp',
    friends: [
      'Sam',
      'Kira',
      'Tomo'
    ],
    location: {
      city: 'San Francisco',
      state: 'CA',
      country: 'USA'
    }
  }
};

function addFriend(userObj, friend) 
{ 
  userObj.data.friends.push(friend);
  return userObj.data.friends;
}

console.log(addFriend(user, 'Pete'));

 

9/01/2019: My Progression Towards FreecodeCamp Javascript Algorithms And Data Structures Certification: Debugging

Introduction

This entry is a copy of my study notebook for CodeRunner for OSX, which I used while I was studying the debugging module in the Javascript Algorithms And Data Structures Certification course on FreeCodeCamp. It covers the exercises I played with while learning debugging in node javascript.


/*

Both Chrome and Firefox have excellent JavaScript consoles, also known as DevTools, for debugging your JavaScript.

You can find Developer tools in your Chrome's menu or Web Console in FireFox's menu. If you're using a different browser, 
or a mobile phone, we strongly recommend switching to desktop Firefox or Chrome.

The console.log() method, which "prints" the output of what's within its parentheses to the console, will likely be the 
most helpful debugging tool. Placing it at strategic points in your code can show you the intermediate values of variables. 
It's good practice to have an idea of what the output should be before looking at what it is. Having check points to see 
the status of your calculations throughout your code will help narrow down where the problem is.

The Console Object
==================

In the browser, the console object is part of the window object, which is a top-level object in the Browser Object Model (BOM).
In Node, the console object is a top-level object in the node API.

The most commonly used member of the console object is the log() method. However, there are four different ways of outputting 
a message to the console:

log
info
warn
error

All four work the same way. All you do is pass one or more arguments to the selected method. 

In the browser, error displays both a red background and a stack trace, whereas info and warn do not. 
Though warn does have a yellow background in Chrome.

String Substitutions
--------------------

This technique uses a placeholder in a string that is replaced by the other argument(s) you pass to the method. For example:

Input: console.log('string %s', 'substitutions')
Output: string substitutions

If you want to pass an object, you need to use %o or %O instead of %s.

console.log('this is an object %o', { obj: { obj2: 'hello' }})

String substitution can be used with integers and floating-point values by using:

%i or %d for integers,
%f for floating-points.

Input: console.log('int: %d, floating-point: %f', 1, 1.5)
Output: int: 1, floating-point: 1.500000

Floats can be formatted to display only one digit after the decimal point by using %.1f. 
You can do %.nf to display n amount of digits after the decimal.

Input: console.log('int: %d, floating-point: %.1f', 1, 1.5)
Output:int: 1, floating-point: 1.5

Formatting specifiers
---------------------

%s | replaces an element with a string
%(d|i)| replaces an element with an integer
%f | replaces an element with a float
%(o|O) | element is displayed as an object.
%c | Applies the provided CSS

String Templates
----------------

With the advent of ES6, template literals are an alternative to substitutions or concatenation. They use backticks (``) instead of quotation marks, and variables go inside ${}:

const a = 'substitutions';
console.log(`bear: ${a}`);
output: bear: substitutions

Using color
-----------

These do not work in the node console.

Winston
-------
Winston is the equivalent to Log4Net/Log4J/NLog in a NodeJs world. It offers the opportunity to use the Appenders.

npm install winston --save
now it's enough to configure it. I've logger.js with its configuration

var winston = require('winston');
winston.emitErrs = true;

var logger = new winston.Logger({
  transports: [
    new winston.transports.File({
      level: 'info',
      filename: './logs/all-logs.log',
      handleExceptions: true,
      json: true,
      maxsize: 5242880, //5MB
      maxFiles: 5,
      colorize: false
    }),
    new winston.transports.Console({
      level: 'debug',
      handleExceptions: true,
      json: false,
      colorize: true
    })
  ],
  exitOnError: false
});

module.exports = logger;
module.exports.stream = {
  write: function(message, encoding){
    logger.info(message);
  }
};
The most important thing is the transports section where you can specify your Appenders. In this example, I want to log into a 
file with verbosity level set to info, max 5 files and 5 MB for each and I want a complete full log (verbosity level debug) in 
the terminal but the different level should use different colors.

Chalk
-----

You apply CSS rules in the string substitution with the %c placeholder.
Then place your CSS elements as a string argument and you can have CSS-styled logs. 
You can add more than one %c into the string as well.

const success = [ 'background: green', 'color: white', 'display: block', 'text-align: center'].join(';');
const failure = [ 'background: red', 'color: white', 'display: block', 'text-align: center'].join(';');
console.info('%c /dancing/bears was Successful!', success);console.log({data: { name: 'Bob', age: 'unknown'}}); // "mocked" data response
console.error('%c /dancing/bats failed!', failure);console.log('/dancing/bats Does not exist');
console.error('%c /dancing/bats failed!', failure);
console.log('%cred %cblue %cwhite','color:red;','color:blue;', 'color: white;')

Other available methods
=======================

Here are a few other available console methods. Note that some items below have not had their APIs standardized, so there may be 
incompatibilities between the browsers. The examples were created with Firefox 51.0.1.

Assert()
Assert takes two arguments — if the first argument evaluates to a falsy value, then it displays the second argument.

let isTrue = false;
console.assert(isTrue, 'This will display');
isTrue = true;
console.assert(isTrue, 'This will not');
If the assertion is false, it outputs to the console. It's displayed as an error-level log as mentioned above, giving you both a red error message and a stack trace.

Dir()
The dir method displays an interactive list of the object passed to it.

console.dir(document.body);

Chrome displays dir differently
Ultimately, dir only saves one or two clicks. If you need to inspect an object from an API response, then displaying it in this structured way can save you some time.

Table()
The table method displays an array or object as a table.

Group()
console.group() is made up of at least a minimum of three console calls, and is probably the method that requires the most typing to use. But it's also one of the most useful (especially for developers using Redux Logger).

console.group();console.log('I will output');console.group();console.log('more indents')console.groupEnd();console.log('ohh look a bear');console.groupEnd();
This will output multiple levels and will display differently depending on your browser.

Each call to console.group() will start a new group, or create a new level if it's called inside a group. Each time you call console.groupEnd() it will end the current group or level and move back up one level.I find the Chrome output style is easier to read since it looks more like a collapsible object.

You can pass group a header argument that will be displayed over console.group:

console.group('Header');

You can display the group as collapsed from the outset if you call console.groupCollapsed(). Based on my experience, this seems to work only in Chrome.

Time()
The time method, like the group method above, comes in two parts.

A method to start the timer and a method to end it.

Once the timer has finished, it will output the total runtime in milliseconds.

To start the timer, you use console.time('id for timer') and to end the timer you use console.timeEnd('id for timer') . You can have up to 10,000 timers running simultaneously.

The output will look a bit like this timer: 0.57ms

It is very useful when you need to do a quick bit of benchmarking.

*/

/*
  JavaScript recognizes six primitive (immutable) data types: Boolean, Null, Undefined, Number, String, and Symbol 
  (new with ES6) and one type for mutable items: Object. Arrays and Sets are objects. Objects and their parameters are
  passed by reference; primitives are passed by value.
*/
console.log("Even though characters and strings are primitives delimited by single quotes and double quotes, respectively, they are both\
 string objects \n that are immutable, are of type: " + typeof('') + ", and are passed by value.");
console.log("Digits and consecutive digits are immutable primitives that are of type: " + typeof(0) + " and are passed by value."); 
console.log("Variables, Arrays, and Sets of anything are mutable, are of type: " + typeof([]) + ", and are passed by reference."); 



 

8/29/2019: My Progression Towards FreecodeCamp Javascript Algorithms And Data Structures Certification: Regular Expressions

Introduction

This entry is a copy of my study notebook for CodeRunner for OSX, which I used while I was studying the regular expressions module in the Javascript Algorithms And Data Structures Certification course on FreeCodeCamp. It covers the exercises I played with while learning the use of regular expressions in node javascript.

console.log("REGULAR EXPRESSIONS MODULE");
console.log("==========================\n");

// test method
var myString = "Hello, World!";
var myRegex = /Hello/;
console.log("test method = " + myRegex.test(myString));

// ignorecase flag
var myString = "freeCodeCamp";
let fccRegex = /freeCodeCamp/i; 
console.log("ignorecase flag = " + fccRegex.test(myString));

// Match method
let extractStr = "Extract the word 'coding' from this string.";
let codingRegex = /coding/; 
console.log("match method = " + extractStr.match(codingRegex)); 

// repeat flag
let twinkleStar = "Twinkle, twinkle, little star";
let starRegex = /twinkle/gi; 
console.log("repeat flag = " + twinkleStar.match(starRegex)); 

// wildcard
let exampleStr = "Let's have fun with regular expressions!";
let unRegex = /.un/;
console.log("wildcard character = " + unRegex.test(exampleStr));

// bracket operator, used with ignore case and repeat flags to get all vowels
var quoteSample = "Beware of bugs in the above code; I have only proved it correct, not tried it.";
let vowelRegex = /[aeiou]/ig;
console.log("bracket operator = " + quoteSample.match(vowelRegex)); 

// bracket operator II, get all letters in the string
var quoteSample = "The quick brown fox jumps over the lazy dog.";
let alphabetRegex = /[a-z]/ig;
console.log("bracket operator using character range = " + quoteSample.match(alphabetRegex));

// shortcut w operator: get all alphanumerics plus the underscore
var quoteSample = "The five boxing wizards jump quickly."; 
let alphabetRegexV2 = /\w/gi; 
console.log("slash w shortcut operator returns this many characters: " + quoteSample.match(alphabetRegexV2).length);

// shortcut W operator: get everything BUT alphanumerics 
var quoteSample = "The five boxing wizards jump quickly.";
let nonAlphabetRegex = /\W/gi; // Change this line
console.log("slash W shortcut operator returns this many characters: " + quoteSample.match(nonAlphabetRegex).length);

// shortcut d and D operators: numbers and everything except numbers
let numString = "Your sandwich will be $5.00";
let AllNumbers = /\d/g;
let EverythingBut = /\D/g;
console.log("all num chars count: " + numString.match(AllNumbers).length + " no num chars count: " + 
            numString.match(EverythingBut).length);

// bracket operator III, get some letters and numbers
var quoteSample = "Blueberry 3.141592653s are delicious.";
var myRegex = /[h-s2-6]/ig;
console.log("bracket operator letters and numbers = " + quoteSample.match(myRegex));

// negation - beginning-of-line operator. Inside of a character set, it means NOT these characters; 
// outside of a character set, it means BEGINNING of the string.
var quoteSample = "3 blind mice.";
var CaretInside = /[^aeiou^0-99]/ig;
var CaretOutside = /^3 bl/;
console.log("caret operator inside a character set = " + quoteSample.match(CaretInside) + 
            "  <===>  caret operator outside a character set = " + quoteSample.match(CaretOutside));

// END of string operator: the '$'
let caboose = "The last car on a train is the caboose";
let lastRegex = /caboose$/;
console.log("dollar sign operator: end of line = " + lastRegex.test(caboose));

// one-or-more characters operator. Note the difference in what it returns when the g flag is omitted.
// so what the combination returns is each block repetition of 's'.
let difficultSpelling = "Mississippi";
var myRegex1 = /s+/g;
var myRegex2 = /s+/;
console.log("bracket operator and one-or-more-characters operator, with and without g flag = " + difficultSpelling.match(myRegex1) + "  <===>  " + difficultSpelling.match(myRegex2));

// ZERO-or-more characters operator. This is a tricky one because note that the 'i' flag for ignorecase
// is not used here, but if it's included doesn't affect it.
let chewieQuote = "Aaaaaaaaaaaaaaaarrrgh!";
let chewieRegex1 = /A[a]*/i; 
let chewieRegex2 = /A[a]*/; 
console.log("Matching zero or more 'a's regardless of case, with and without i flag = " +  chewieQuote.match(chewieRegex1) + "  <===>  " + chewieQuote.match(chewieRegex2));

//lazy vs greedy matching: the '?' operator. Greedy returns all characters possible, Lazy returns the fewest characters possible.
let text = "

Winter is coming

"; let myGreedyRegex = /<.*>/; let myLazyRegex = /<.*?>/; console.log("Greedy vs. Lazy regex = " + text.match(myGreedyRegex) + " <==> " + text.match(myLazyRegex)); // find repeating blocks of one or more C characters in a random string. Solved with one try. let crowd = 'P1P2P3P4P5P6CCCP7P8P9'; let reCriminals = /C+/g; let matchedCriminals = crowd.match(reCriminals); console.log("Matched C characters in random string = " + matchedCriminals); /* putting it all together: how each rule reads rule 1: "if there are zero or more numbers in the username, they have to be at the end" /\d*$/ rule 2: "usernames can be lowercase or uppercase" i rule 3: "Usernames have to be at least two characters long" {2,} rule 4: "A two-letter username can only use alphabet letter characters" ^[a-z] */ var username = "JackOfAllTrades"; var userCheck = /^[a-z]{2,}\d*$/i; console.log("Check chosen username: " + userCheck.test(username)); // the whitespace operators: s yes and S no var sample = "Whitespace is important in separating words"; var countWhiteSpace = /\s/g; var countNoWhiteSpace = /\S/g; console.log("count of YES: " + sample.match(countWhiteSpace).length + " <==> count of NO: " + sample.match(countNoWhiteSpace).length); //match limits brackets let ohStr = "Ohhh no"; let ohRegex1 = /Oh{3,6}\sno/; let ohRegex2 = /Oh{3,}\sno/; let ohRegex3 = /Oh{,6}\sno/; let ohRegex4 = /Oh{6}\sno/; console.log("Return between 3 and 6 matches of h in oh no: " + ohRegex1.test(ohStr)); console.log("Return at least 3 matches of h in oh no: " + ohRegex2.test(ohStr)); console.log("Return no more than 6 matches ofh in oh no: " + ohRegex3.test(ohStr)); console.log("Return 6 matches ofh in oh no: " + ohRegex4.test(ohStr)); // optional characters operator: also return the 'u' if it's there let favWord = "favorite"; let favRegex = /favou?rite/; // Change this line console.log("Return english and british spellings of the word favorite: " + favRegex.test(favWord)); // LOOKAHEADS: This example has two, delimited by parentheses. let sampleWord = "astronaut12"; let pwRegex = /(?=\w{5,})(?=\D*\d{2})/; console.log("1. greater than 5 characters long and 2. have 2 consecutive digits: " + pwRegex.test(sampleWord)); // CAPTURE GROUPS: used to search for repeat substrings. This example: // match numbers that are repeated only three times, each separated by a space. var repeatNum = "42 42 42"; var reRegex = /^(\d+)\s\1\s\1$/; console.log("match numbers that are repeated only three times, each separated by a space.: " + reRegex.test(repeatNum)); /* Using the .match() method on a string will return an array with the string it matches, along with its capture group. The example below matches any word that occurs twice, separated by a space, in this case 'regex': */ let repeatStr = "regex regex"; let repeatRegex = /(\w+)\s\1/; console.log(repeatStr.match(repeatRegex)); // Returns ["regex regex", "regex"] /* Replace method. The first parameter, which is not quoted, is the regex search pattern. The second parameter is the quoted string to replace it with. */ console.log("replace silver with blue: " + "The sky is silver.".replace(/silver/, "blue")); // This next example is the equivalent of the .trim method: let hello = ; let wsRegex = /^\s+|\s+$/g; // Change this line console.log(" Hello, World! ".replace(/^\s+|\s+$/g, ''));

8/18/2019: My Notebook for Functional Programming In Javascript

Introduction

This entry is a copy of my study notebook for CodeRunner for OSX, which I used while I was studying Javascript ES6. It covers the exercises I played with while learning functional programming and ES6 concepts.

/* 
  literals don't have properties and methods per se, but pass by value
  objects have properties and methods but pass by reference
*/

let strLiteral = 'uhhh';
let objStrLiteral = String('uhhh');
let intLiteral = 1;
let objIntLiteral = Number(1);
console.log(strLiteral);
console.log(objStrLiteral);
console.log(intLiteral);
console.log(objIntLiteral);

// let and const implement local scoping for variables that are assigned literals; 
// no qualifier or var means no scoping at all, global scope, EXCEPT for VAR variables
// that are assigned functions. The function has local scope.

// destructuring arrays: pulling the elements out into separate entities
// destructuring includes for-of, swapping, regexp
const [x,y] = [1,2];
// using destructuring to swap
let v = 1, w = 2;
[v,w] = [w,v];
// regular expression as source
const [a, b, c, d] = 'one two three'.match(/\w+/g);
// destructure all vowels using regexp
const [e, f, g] = 'one two three'.match(/[aeiou]/);

// using the join() method of arrays to destructure
let arrJoin = new Array();
arrJoin = ['one', 'two', 'three'];
flatfileCSV = arrJoin.join(',');
console.log(flatfileCSV);
// destructuring a multidimensional array: tripleDots
const summer = ['Jun', 'Jul', 'Aug']; 
const winter = ['Dec', 'Jan', 'Feb']; 
const nested = [ summer, winter ]; 
console.log(nested);
console.log([...summer, ...winter]);

// pop and push implement arrays as stacks, shift and unshift implement arrays as queues
// merge concatenates arrays

// slice() copies items into a subarray, splice() cuts items into a subarray

// indexOf() finds items in an array - position or -1
// includes() returns true if the items is in the array otherwise false

// sets - clear, delete methods
const setNewSet = new Set();
// repeating dot to repeat method
setNewSet.add(2).add(3).add(4);
// creating a multidimensional set in one go
const setMultiDim = new Set([1,2,3], [4,5,6], [7,8,9]);
// no, not length - it's called size
console.log('the size of this thing is:', setMultiDim.size);
// tripledotting to convert a set (below) into an array - look what happens
const arrSetMultiDim = [...setMultiDim];
console.log(arrSetMultiDim);
// sets by default are not garbage collected. WeakSets are: Only non-primitive data types can be added to weak sets.
const weakCool = new WeakSet([new Array(1,2,3)]);
// but what use is it then - undefined? the array values are inaccessible - but the array can be removed
console.log(weakCool[0]);

// all maps are objects. Maps are the javascript equivalent of python dictionaries. their methods are get, has, delete
const mapNumerals = new Map();
mapNumerals.set(1,'I');
mapNumerals.set(2, 'II').set(3, 'III');
console.log(mapNumerals)
// tripledotting to convert to multidimensional array. This could then be deconstructed
console.log([...mapNumerals]);
// if you want your map garbage collected
const weak = new WeakMap();

// looping over sets and maps
for(const mappy of mapNumerals) { console.log(mappy); }

// ternaries
const n = 5; 
n%2 === 0 ? console.log('n is an even number') : console.log('n is an odd number');


// ==============================================================
// functional programming
// ==============================================================

const goodbye = function bye(){ console.log('Goodbye World!'); };
console.log(goodbye(), goodbye);

const goodbyeReturn = function bye(){ return 'Goodbye World!'; };
console.log(goodbye(), goodbye);

// arrow functions (anonymous functions)
const square = x => x*x;
const add = (x,y) => x + y;
console.log(square(4));
console.log(add(4,5));

//SUBs and functional collections
const subUsingPrint = () => console.log('Hello World!');
const subUsingReturn = () => { return 'Goodbye World!'};
const arrFunctions = new Array(subUsingPrint(), subUsingReturn());
console.log(subUsingPrint());
console.log(subUsingReturn());
console.log(arrFunctions[0]);

/* Hoisting
  Variable declarations that use the var keyword are automatically moved to the top of the current scope. Variable assignment is not hoisted, however. 
  This means that a variable assigned at the end of a function will have a value of undefined until the assignment is made. Functions are always hoisted.
*/

// CALLBACKS. the function 'numerically' is the callback, a function that is used as a parameter.

function numerically (a,b) 
{ 
  if (a < b){return -1; } 
  else if (a> b) {return 1; } 
  else {return 0; } 
}
console.log([1,3,12,5,23,18,7].sort(numerically));

// the functional programming equivalent of ForEach'ing over a collection in VB
['Red', 'Green', 'Blue'].forEach( (color,index) => console.log(`Color at position ${index} is ${color}`) );

const cube = x => x*x*x;
console.log([1,2,3].map(cube));
// WTF??
const concat = (x,y) => String.toString(x) + String.toString(y); 
console.log(['the ', 'end'].map(concat));
//OK - this works
console.log(['red','green','blue'].map( color => `

➥ ${color.toUpperCase()}

`)); // reduce(). Check this out let intInitialValue = -2; console.log([1,2,3,4,5].reduce( (acc,val) => acc + val,intInitialValue)); // using filter() with a boolean callback - returns even numbers then odd numbers console.log([ 2, 7, 6, 5, 11, 23, 12 ].filter(x => x%2 === 0 )); console.log([ 2, 7, 6, 5, 11, 23, 12 ].filter(x => x%2 === 1 )); // chaining iterators together console.log([1,2,3].map( x => x*x ).reduce((acc,x) => acc + x )); /* OBJECTS - methods: hasOwnProperty, Object.keys(object), Object.values(object), delete - operators: this - objects can be nested, so whole object models can be created. Unfortunately, they are mutable (see below) - objects can be used as parameters to functions, so methods of object parameters are considered callbacks */ //properties const name = 'Iron Man'; const realName = 'Tony Stark'; //methods const shootLaserBeam = () => console.log('bzzzzzzt!!'); //member with default values for input parameters const introduceMe = (greeting='Hello',name='IronMan',age=38) => console.log(`${greeting}! My name is ${name} and I am ${age} years old.`); //Coderunner does not support this way of object creation: const ironMan = ( name: name, realName: realName }; //...but it supports this way: const ironMan = { name, realName, shootLaserBeam, ['catch' + 'Phrase']: 'I love you 3000!', introduceMe }; //accessing a property console.log(ironMan.name); //accessing a method ironMan.shootLaserBeam(); //accessing a computed property key console.log(ironMan.catchPhrase) //brackets work too console.log(ironMan['catchPhrase']) //the 'in' operator if('catchPhrase' in ironMan){console.log("it's in there");} if('fly' in ironMan){}else{console.log("nah it's not there");} let superman = ironMan; // iterating over an object's members using 'in' for(const key in superman) { console.log(key + ": " + superman[key]); } // iterating over an object's members using destructure for(const [key,value] of Object.entries(superman)) { console.log(`${key}: ${value}`); } /* OBJECTS ARE MUTABLE EVEN WITH USE OF CONST OPERATOR! (member values can change on the fly! and because objects are nestable, a member of an object - even a collection - can be mutated on-the-fly. */ ironMan.fly = () => console.log('wheeeeeeee!'); ironMan.fly(); ironMan.fly = () => console.log('even methods are mutable!'); ironMan.fly(); ironMan.introduceMe(); ironMan.introduceMe('Hi', 'Superman', 35); //parameters are positional and literals are still immutable ironMan.introduceMe(greeting='Ugh!', 'Hulk', age=30); // NAMESPACE OBJECTS // basic pattern const namMyMathAPI = { //this is the only way you can set a constant property in this pattern PI(){return 3.414;} , square(x) { return x * x; }, mean(array,callback) { if (callback) { array.map( callback );} const total = array.reduce((a, b) => a + b); return total/array.length; } }; // object literal pattern (all members public without a closure) const namLiteral = { id: 0 , name: function(){return 'literal';} , PI: 3.14141414 } console.log(namLiteral.PI); console.log(namLiteral.name()); //throw new Error('Something has gone badly wrong!'); /* The call() method can be used to set the value of 'this' inside a function to an object that is provided as the first argument. The apply() method works in the same way, except the arguments of the function are provided as an array, even if there is only one argument. Memoization is a useful feature that provides result caching. If a function takes some time to compute a return value, we can save the result in a cache property. Then if the same argument is used again later, we can return the value from the cache, rather than having to compute the result again. An Immediately Invoked Function Expression – or IIFE (pronounced "iffy") – is an anonymous function that, as the name suggests, is invoked as soon as it's defined. Placing any code that uses a temporary variable inside an IIFE will ensure it's only available while the IIFE is invoked, then it will disappear. IIFEs are deprecated in ES6, having been replaced by destructuring. Functional programming uses pure functions as the building blocks of a program. A closure is a reference to a variable that was created inside the scope of another function, but is then kept alive and used in another part of the program. A closure is formed when the inner function is returned by the outer function, maintaining access to any variables declared inside the enclosing function. */ /* Advanced, niche techniques - Init-Time Branching using IIFEs - Event-driven Asynchronous Programming Using Callbacks - Promises and the Promise Class - the async and await keywords - Closures, partial applications, and currying */ // EXAMPLE CLOSURE. This pattern has superceded the old encapsulation of private variables pattern in OOP - must // understand how this works. function outer() { const outside = 'Outside!'; function inner() { const inside = 'Inside!'; console.log(outside); console.log(inside); } console.log(outside); inner(); } outer(); //example promise //const wait = time => new Promise((resolve) => setTimeout(resolve, time)); //wait(3000).then(() => console.log('Hello!')); // example of named parameters, like in VB. They must be implemented as functional const's, not literals. // This example uses the CALL() method function sayHello1() { return `The named parameter returns: ${ this.name }`; } const clark = { name: 'Clark' }; const bruce = { name: 'Bruce' }; console.log(sayHello1.call(clark)); // This example adds a custom greeting parameter with a default function sayHello2(greeting='Hello') { return `${ greeting }, my name is ${ this.name }`; } const cutie = { name: 'Cutie-Pie' }; console.log(sayHello2.call(cutie, 'How do you do')); // This example uses the custom greeting with a collection const theCrew = [ {name: "Billy"}, {name: "Bryan"}, {name: "Topher"} ]; console.log(sayHello2.call(theCrew[0], 'Good Morning')); // An update to the collection example: each member has multiple properties const theCrewCustom = [ {name: "Billy", greetin: "Hey"}, {name: "Bryan", greetin: "What Up"}, {name: "James", greetin: "Mornin"} ]; // Calling the collection, without Currying console.log(sayHello2.call(theCrewCustom[2], theCrewCustom[2].greetin)); // Calling the collection, with Currying const curryCrew = curryGreeting => obj => obj.name === "Billy"; console.log(theCrewCustom.filter(curryCrew())); //IIFE use in ES5 let swap3 = 1; let swap4 = 2; (()=>{ const temp = swap3; swap3 = swap4; swap4 = temp; })(); // deprecation of IIFE with destructuring in ES6 let [swap1,swap2] = [1,2]; [swap1,swap2] = [swap2,swap1]; // Generator functions function* fibonacci(a,b) { let [ prev,current ] = [ a,b ]; while(true) { [prev, current] = [current, prev + current]; yield current; } } const sequence = fibonacci(1,1); console.log(sequence.next()); console.log(sequence.next()); for (intLoop of sequence) { if (intLoop > 10) break; console.log(intLoop); } // Higher order functions, closures, and callbacks /* Multiple Parenthesis trick. The x to the y power function, implemented using functional programming. First dimension is x, the base. Second dimension is power(x), the exponent. */ function power(x) { return function(power) { return Math.pow(x,power); } } // 2 to the 5th power console.log(power(2)(5)); // 10 to the 6th power console.log(power(10)(6)); /* Dice roller as a multiple parenthesis trick. so to roll 5d6 you call: Dice(5)(6). TODO: use this as the dice rolling engine, then develop a parser that will parse a string like "5d6 + 4", roll 5 6-sided dice, add 4, and return the result. That code would replace dice rolling in role playing games. */ function Dice(numberOf) { return function(Dice) { let accum = 0; for(intLoop = 0; intLoop < numberOf; intLoop++) { accum += Math.floor(Dice * Math.random() + 1); } return accum; } } const diceCount = 5; const diceSides = 100; console.log("\n**********RANDOM NUMBER GENERATOR**********\n"); console.log(diceCount + "d" + diceSides + " = ", Dice(diceCount)(diceSides)); console.log("\n\n"); /* AJAX using the new Fetch API. This is a little weird, but: no semicolon after the .then method, and the second fetch() will return BEFORE the Status and Redirected properties, even though those statements appear later in the code. And, the second fetch() is REQUIRED or it won't work. */ console.log("\n********** AJAX **********\n"); const fetch = require("node-fetch"); let url = 'http://www.deckerd26354.net/sites'; console.log("Server reply:\n "); fetch(url) .then ( (response) => { if(response.ok) { console.log("\tStatus: " + response.statusText); console.log("\tRedirected: " + response.redirected); return; } } ) // The following code has to be commented out or the next fetch won't work // fetch(url) // .then(response => response.text()) // .then(text => console.log(text)) fetch('https://jsonplaceholder.typicode.com/todos/1') .then( response => response.json() ) .then( data => console.log(Object.entries(data)[0]) ) /* CURRYING Is a technique for converting function calls with N arguments into chains of N function calls with a single argument for each function call. Currying always returns another function with only one argument until all of the arguments have been applied. So, we just keep calling the returned function until we've exhausted all the arguments and the final value gets returned. Currying is used for: Function Composition, Project Setup, Memoization. The RAMDA.JS framework (https://ramdajs.com/) automatically curries. It also allows you to code in functional using a SQL-like syntax. Factory method in ES6: const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args))); Currying always produces nested unary (1-ary) functions. The transformed function is still largely the same as the original. Partial applications produce functions of arbitrary number of arguments. The transformed function is different from the original — it needs less arguments. Currying does not produce partial applications because you can't curry a function that takes any number of arguments. However, you can implement currying using partial applications. */ libRamda = require("ramda"); // Normal function function addition(x, y) { return x + y; } // Curried function function addition(x) { return function(y) { return x + y; } } /* PARTIAL APPLICATIONS A technique of fixing a number of arguments to a function, producing another function of smaller arguments i.e binding values to one or more of those arguments as the chain of function progressed. JavaScript has the built-in method .bind that works on functions with any number of arguments and can bind an arbitrary amount of parameters. Its invocation has the following syntax: function.bind(thisValue, [arg1], [arg2], ...) It turns function into a new function whose implicit this parameter is this value and whose initial arguments are always as given. function addition(x, y) { return x + y; } const plus5 = addition.bind(null, 5) plus5(10) // output -> 15 Note: this value does not matter for the (non-method) function addition which is why it is null above. A Detailed explanation of partial applications can be found at: http://benalman.com/news/2012/09/partial-application-in-javascript/#partial-application */ // example partial application function const partialApply = (fn, ...fixedArgs) => { return function (...remainingArgs) { return fn.apply(this, fixedArgs.concat(remainingArgs)); }; }; // here, you only pass the number 5 via a, then pass the number 'bumpUp' via the b parameter later. Here, // bumpUp is local, but it could be provided by a promise from a service somewhere. let bumpUp = 20; const addIt = (a, b) => a + b; const add10 = partialApply(addIt, bumpUp); console.log(add10(5));