Thursday, July 20, 2017

Crunch or Crackle?

Will the potato chip crunch or crackle?
var cornChip = {
  sound: "crunch",
  eat: function() {
    console.log(this.sound);
  },
}
console.log(cornChip.eat());
var potatoChip = {
  sound: "crackle",
  eat: cornChip.eat,
}
console.log(potatoChip.eat());

Saturday, July 1, 2017

forEach() with filter() Lookup

Let's avoid some data duplication and use a keyed lookup to retrieve a book's author.
class Author {
  constructor(name, birth, death, nationality) {
    this.name = name,
    this.birth = birth,
    this.death = death, 
    this.nationality = nationality
  }
}

class Book {
  constructor(title, pubDate, authorKey) {
    this.title = title,
    this.pubDate = pubDate,
    this.authorKey = authorKey
  }
}

authors = [
  new Author({first: "William",  last: "Shakespeare"}, 1564, 1616, "English"),
  new Author({first: "Francis",  last: "Bacon"},     1561, 1626, "English"),
  new Author({first: "Thomas",   last: "More"},      1478, 1535, "English"),
  new Author({first: "Geoffrey", last: "Chaucer"},   1343, 1400, "English"),
  new Author({first: "Mary",     last: "Shelley"},   1797, 1851, "English"),
  new Author({first: "Jane",     last: "Austen"},    1775, 1817, "English"),
  new Author({first: "JK",       last: "Rowling"},   1965, 0,    "English"),
  new Author({first: "George",   last: "Orwell"},    1797, 1851, "English"),
  new Author({first: "Charles",  last: "Dickens"},   1797, 1851, "English"),
  new Author({first: "George",   last: "Eliot"},     1819, 1880, "English")
];

books = [
  new Book("Middlemarch",               1871, 9),
  new Book("Silas Marner",              1861, 9),
  new Book("A Christmas Tale",          1843, 8),
  new Book("Oliver Twist",              1837, 8),
  new Book("Great Expectations",        1860, 8),
  new Book("A Tale of Two Cities",      1859, 8),
  new Book("David Copperfield",         1849, 8),
  new Book("Nineteen Eighty-Four",      1949, 7),
  new Book("Animal Farm",               1945, 7),
  new Book("The Complete Plays",        2016, 1),
  new Book("Four Great Comedies",       2009, 1),
  new Book("Essays",                    1597, 1),
  new Book("Novum Organum Scientiarum", 1620, 1),
  new Book("A Merry Jest ",             1516, 2),
  new Book("Utopia",                    1516, 2),
  new Book("The Canterbury Tales",      1400, 3),
  new Book("Frankenstein: or, The Modern Prometheus",   1818, 4),
  new Book("Sense and Sensibility ",                    1811, 5),
  new Book("Pride and Prejudice ",                      1813, 5),
  new Book("Harry Potter and the Philosopher's Stone ", 1997, 6),
  new Book("Harry Potter and the Chamber of Secrets",   1998, 6),
  new Book("Harry Potter and the Prisoner of Azkaban",  1999, 6),
  new Book("Harry Potter and the Goblet of Fire",       2000, 6),
];

for (let i = 0; i < books.length; i++) {
  let auth = authors.filter( (elem, index) => books[i].authorKey === index);
  console.log(`title: ${books[i].title}, author: ${auth[0].name.first} ${auth[0].name.last}`);
};

books.forEach((book, index) => {
  let auth = authors.filter( (elem, i) => book.authorKey === i);
  console.log(`title: ${book.title}, author: ${auth[0].name.first} ${auth[0].name.last}`);
});

Wednesday, June 28, 2017

JS Basics

Obj literal, Constructor, Class and Properties

'use strict';

// object literal
var cat = {name: 'Fluffy', color: 'white'}
console.log(cat.color)
cat.age = 3
console.log('name=' + cat.name + ' and age=' + cat.age)
cat.speak = function() {console.log('Meoow')}
cat.speak()

// constructor
function Cat2(name, color) {
  this.name = name, 
  this.color = color
}
var sam = new Cat2('Sam', 'tabby');
console.log(sam.color)

// class
class Cat3 {
  constructor(name, color, age) {
    this.name = name,
    this.color = color,
    this.age = age
  }
  speak() {
    console.log('Meoow')
  }
}

var fred = new Cat3({first: 'Frederico', last: 'DeSoto'},'silver', 5)
fred.speak()

for (let property in fred) {
  console.log(property + ": " + fred[property])
}

console.log(JSON.stringify(fred));

Object.defineProperty(fred, 'fullName',
{
  get: function() {
    return this.name.first + " " + this.name.last  
  },
  set: function(val) {
    let parts = val.split(' ');
    this.name.first = parts[0];
    this.name.last = parts[1];
  }
})

console.log(fred.fullName)
fred.fullName = 'George Smiley'
console.log(fred.fullName)  // George Smiley

Tuesday, June 27, 2017

Screen Scraping

I wanted a list of the episode titles of "Agatha Christie's Poirot", my favorite TV detective series. I decided to scrape the HTML from wikipedia's entry. The data looks like this:
<tr>
<th scope="row" style="text-align:center;"><a 
href="/wiki/Poirot%27s_Early_Cases#The_Adventure_of_the_Clapham_Cook" 
title="Poirot's Early Cases">The Adventure of the Clapham Cook</a></th>
<td style="text-align:center;">8 January 1989</td>
<tr>
<th scope="row" style="text-align:center;"><a 
href="/wiki/Murder_in_the_Mews_(TV_1989)" 
class="mw-redirect" 
title="Murder in the Mews (TV 1989)">Murder in the Mews</a></th>
<td style="text-align:center;">15 January 1989</td> 
I want the text from the <a> tag that resides inside the <th> tag.

I found a Javascript library named cheerio that seemed to do what I require.
$ npm install request cheerio
// index.js
let request = require('request');
let cheerio = require('cheerio');
let lastEpisode = false;
request({
    uri: "https://en.wikipedia.org/wiki/List_of_Agatha_Christie's_Poirot_episodes"
  }, function (err, response, html) {
    if (err || response.statusCode !== 200) {
      console.log('E R R O R ' + response.statusCode);
      return;
    }
    var $ = cheerio.load(html);
    $('th a').each(function(i, elem) {
      let episode = $(this).text();
      // eliminate "[fn" (footnotes)
      if (!lastEpisode && episode.substring(0, 3) !== '[fn') {
        console.log(episode);
      }
      lastEpisode = lastEpisode || (episode.substring(0, 7) === "Curtain");
    });
});
$ node index.js
The Adventure of the Clapham Cook
Murder in the Mews
The Adventure of Johnnie Waverly
Four and Twenty Blackbirds
The Third Floor Flat
Triangle at Rhodes
Problem at Sea
The Incredible Theft
The King of Clubs
The Dream
Peril at End House
The Veiled Lady
The Lost Mine
The Cornish Mystery
The Disappearance of Mr. Davenheim
Double Sin
The Adventure of the Cheap Flat
. . .
Cat Among the Pigeons
Third Girl
Appointment with Death
Three Act Tragedy
Hallowe'en Party
Murder on the Orient Express
The Clocks
Elephants Can Remember
The Big Four
Dead Man's Folly
The Labours of Hercules
Curtain: Poirot's Last Case

Functional Array Processing

Write a function that will search an array of integers for two values that equal 2nd argument.
let arrayInput = [3, 34, 4, 12, 5, 2];

// function to find two values in inputArray that equal target
function findPairForSum(integers, target) {
  let result = [];

  var subtree = (givenArray, el2Eliminate) => {
    let copy = [];
    givenArray.forEach( (el, i, ar) => {
      if (i !== el2Eliminate) {
        copy.push(el);
      }
    });
    return copy;
  }

  integers.forEach( (el, i, ar) => {
    let eliminate = i;
    let choppedArray = subtree(ar, i);
    choppedArray.forEach( (el, i, ar) => {
      if (eliminate + el == target) {
        result.push(eliminate);
        result.push(el);
        return result;
      }
    });
  });
  return result;
}

// test 1
var pair = findPairForSum(arrayInput, 9);
console.log(`9 = ${pair}`); // --> [4, 5]

// test 2
pair = findPairForSum(arrayInput, 14);
console.log(`14 = ${pair}`); // --> [12, 2]

// test 3
pair = findPairForSum(arrayInput, 99);
console.log(`99 = ${pair}`); // --> [,]

Javascript Shortcuts

Creating a new function as shown in the receive function in the first clock of code creates a new lexical scope, a new 'this', which necessitates 'var that = this;'.

Lambdas do not create a new lexical scope, ie, lexical scope is retained when using lambdas.

Old Style

Old style Javascript without lambdas requires use of that = this;.
let screenObj = {
  name: "Button",

  handleMessage: function(message, handler) {
   handler(message);
  },

  receive: function(greeting) {
    var that = this;
    this.handleMessage(greeting, function(message) {
      console.log(message + that.name)
    })
  }
};

screenObj.receive("Hello, ");  // Hello, Button
Eliminate that = this; code and avoid having to deal with changes to lexical scope by using lambdas.
Replace function(message) with message => to define the lambda.
let screenObj = {
  name: "Button",

  handleMessage: function(message, handler) { handler(message)},

  receive: function(greeting) {
    this.handleMessage(greeting, 
     message => console.log(message + this.name))
  }
};

screenObj.receive("Hello, ");    // Hello, Button

Simplifying

let first = 'Johnnie'
let last = 'Cash'

// this definition can be simplified
const firstAndLast = { first: first, last: last }
console.log(firstAndLast.last)    // Cash

// name only the keys
const firstLast = { first, last }
console.log(firstLast.last)      // Cash

Spread Operator

const odd = [1, 3, 5];
const even = [2, 4, 6];
const nums = [...even, ...odd]; // [2, 4, 6, 1, 3, 5]

The Import Statement

const foo = require('blah/foo');
const bar = require('blah/bar');

// can be replaced with

import {foo, bar} from 'blah';

Default Parameters

let noDefaults = function(greeting, name) {
  console.log(`${greeting}, ${name}`);
}
let withDefaults = function(greeting="Hello", name="George") {
  console.log(`${greeting}, ${name}`);
}
noDefaults();               // undefined, undefined
withDefaults("Hi", "Joe");  // Hi, Joe
withDefaults();             // Hello, George

Destructuring an Array

let names = ['Charles', 'Debbie', 'Susan', 'Keith']
var [boy1,,,boy2] = names
console.log(boy1)  // Charles
console.log(boy2)  // Keith

Destructuring an Object

let managerie = () => {
  return {
    dog: 'terrier',
    cat: 'tabby',
    fish: 'shark',
    bird: 'parrot',
  }
};

let {dog, fish} = managerie();
console.log(dog);   // terrier
console.log(fish);  // shark

Destructuring an Object in the Argument List

let sneakers = [
  {
    name: 'Air Jordans',
    brand: 'Nike',
  },
  {
    name: 'Flyers',
    brand: 'Converse',
  },
  {
    name: 'Runners',
    brand: 'Sketchers',
  },
  {
    name: 'Trail Runner',
    brand: 'New Balance',
  }];

let [,,cheapShoe] = sneakers
let log = function({brand}) { // destructure the object passed
  console.log(brand) 
}
log(cheapShoe)    // Sketchers

ES6 Generators

function*, yield and next()
function* repeat() {
  const arr = ["A", "B", "C", "D"];
  for (let x in arr) {
  yield arr[x];
  }
}

var foo = repeat();
let bar = foo.next();
while (!bar.done) {
  console.log(bar.value); // logs a letter with each iteration 
  bar = foo.next();
}

The Array.reduce Function

let votes=['react','react','react','vue','meteor','angular','angular']
let voteCount = function(tally, vote) {
  if (!tally[vote]) {
    tally[vote] = 1
  } else {
    tally[vote] += 1
  }
  return tally
}
let results = votes.reduce(voteCount, {})
for (framework in results) {
  console.log(framework + "=" + results[framework])
}

// react=3
// vue=1
// meteor=1
// angular=2

Map and Reduce

const data = ["a", "b","c"]
let doubled = data.reduce(function(acc, elem) {
  acc.push(elem + elem)
  return acc;
}, []);

let doubleMapped = data.map(function(elem) {
  return elem + elem;
});

let filterMapped = data.filter(function(elem) {
  return elem !== "b";
}).map(function(elem) {
 return elem + elem.toUpperCase();
});

console.log(doubled)      // [aa,bb,cc]
console.log(doubleMapped) // [aa,bb,cc]
console.log(filterMapped) // [aA,cC]

Saturday, December 17, 2016

Rediscovering Javascript by Venkat Subramaniam

Venkat is brilliant https://youtu.be/r9XAp3CWRf4?t=30m14s

Using the Implicit Context Object


var greet = function(name) {
  console.log(this.toUpperCase() + ' ' + name);
}
// greet('Joe'); // blows up
greet.call('hello', 'Joe'); // 'hello' becomes the implicit 'this'
> HELLO Joe

Using Arguments Array and Apply

var greet = function(name1, name2) {
  console.log(this.toUpperCase() + ' ' + name1 + ' ' + name2);
}
greet.apply('hi', ['Jack', 'Jill']); 
> HI Jack Jill

Thursday, December 15, 2016

React Elements vs React Components

React Elements vs React Components reveals how React renders elements and components. The way properties can be code or data gives Javascript a flavor of LISP's homoinconicity.

Javascript ORM

TypeORM a Data-Mapper ORM for TypeScript, ES7, ES6 and ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle databases.

Wednesday, December 14, 2016

Accumulate Array of Arrays Using forEach

Flatten - Combining Arrays with forEach()

var data = [[1,2,3], [4,5,6], [7,8,9]];
function arrayAdd(aOfAs) {
  var acc = [];
  aOfAs.forEach(function(a) {
    a.forEach(function(el) {
      acc.push(el);
    ;})
  ;});
  return acc;
}
arrayAdd(data);
> [1,2,3,4,5,6,7,8,9]

Same Thing - Flatten with reduce()

var data = [[1,2,3],[4,5,6],[7,8,9]];
var flattenedData = data.reduce(function(acc, value) {
  return acc.concat(value);
}, []);
console.log(flattenedData);
> [1, 2, 3, 4, 5, 6, 7, 8, 9]

Processing every element of an array with reduce()

var data = [1,2,3,4,5];
var doubled = data.reduce(function(acc, value) {
  acc.push(value * 2);
  return acc;
}, []);
console.log(doubled);
> [2, 4, 6, 8, 10]

Selecting some elements of an array with reduce()

var data = [1,2,3,4,5];
var evens = data.reduce(function(acc, value) {
  if (value % 2 === 0) {
    acc.push(value);
  }
  return acc;
}, []);
console.log(evens);
> [2, 4]

Same Thing Using filter()

var evenFiltered = data.filter(function(item) {
  return item % 2 === 0;
});
console.log(evenFiltered);
[2, 4]

Filtered and Mapped

var filteredAndMapped = data.filter(function(value) {
  return value % 2 == 0;
}).map(function(value) {
  return value * 2;
});
console.log(filteredAndMapped);
> [4, 8]

Array's Functional Functions

What is the difference between Array's functions .map, .every, and .forEach?

.map() returns a new Array of objects created by taking some action on the original item.

.every() returns a boolean - true if every element in this array satisfies the provided testing function. An important difference with .every() is that the test function may not always be called for every element in the array. Once the testing function returns false for any element, no more array elements are iterated. Therefore, the testing function should usually have no side effects.

.forEach() returns nothing - It iterates the Array performing a given action for each item in the Array.

First Job Red Flags for the New Javascript Developer

You attended a coding bootcamp, paying more than $10,000 for the privilege and now you are on the cusp of starting your new career. Do you value the education you received? Your new employer will certainly be happy to get you and they will think they are training you in a way that continues the progress you've made but, good intentions are sometimes mixed with ignorance. What are the indications your potential employer is going to detour you to a dead-end?

The Programmer's Bill of Rights on Coding Horror is inadequate for determining if a job will be a good one. Based on my own experience and observations, I created a list of indicators of a bad IT developer job.

Red Flags
No source control
No unit test, no automated unit tests
No automated build
No application spec
No code reviews
No bug database
Not asked to code or whiteboard on the interview
Wants you to focus on the backend
No control over your development machine
Has a mainframe or similar
Is an Oracle or IBM shop [1.]
uses a language your grandpa might have used if he were a developer
uses or desires to use a rules engine
uses stored procedures (you may want to stay away from SQL and relational DBs completely)
uses failed Java stuff - EJBs, Websphere, JEE, JSF, Eclipse

Really Red Flag
An old school shop wants to hire you as the first person in a planned cardre of developers with modern skills [2.]

Green Flags
none of the red flags
Your job includes:
- pair programming
- coding in functional language & functional style
- working on UI and on distributed services
- working with users to spec and develop from new requirements


[1.] if you work where they invest in 1980s or 1990s technology, the people who know the old stuff will be the most highly rewarded people there and they are rewarded largely for fixing their own mistakes. Their Friday installs will result in Saturday and Sunday all-hands conference calls that will screw-up your weekends and on Monday they will get an 'atta-boy' for fixing their bug. See Flintstoning
[2.] if the shop cannot evolve with the developers they have then they cannot evolve so don't be the victim of their history of rationalizations and laziness.

Monday, December 12, 2016

Recursion on Sorted Array

Find if any two elements in a sorted array can equal a sum.

Write a function checkSumOf2 that accepts two parameters, a sorted array and a number that is the target that two numbers in the array should sum to.
function checkSumOf2(ary, target) {
  function check2(ary, target, left, right) {
    if (left >= right) {
      return false;
    }
    var sum = ary[left] + ary[right];
    if (sum === target) {
      return true;
    } else if (sum > target) {
      right--;
    } else {
      left++;
    }
    return check2(ary, target, left, right);;
  }

  return check2(ary, target, 0, ary.length - 1);
}

console.log( '1.' + checkSumOf2([1,3,5,7], 8) )  // true
console.log( '2.' + checkSumOf2([0,2,6,8], 7) )  // false
console.log( '3.' + checkSumOf2([4,5,6,7], 12) ) // true
console.log( '4.' + checkSumOf2([1,2,3,4], 12) ) // false
console.log( '5.' + checkSumOf2([1,2,3,4], 4) )  // true

Thursday, November 17, 2016

Recursive Problems

The lecture included a statement which was very helpful in solving all the recursive assignments, that the function will consist of two parts,
· the if clause that produces the termination of the recursive calls
· the recursive call
The structure that statement describes was the template we used in all of our solutions.

The problem statement in the Fibonacci exercise gave us another tool that we reused in subsequent exercises, a chart of the values of the function's fields over the steps of the recursive call. Although we had these tools that were useful later, we had to ask for help and Garrett coached us to the solution.

The problem statement tells us that for n > 1, fib(n) is fib(n - 1) + fib(n - 2)

What follows is the chart given to us in the problem then the Fibonicci function, followed by a version of the Fibonicci function that includes some logging statements. The console.log statements provide a view into the functioning of the function.



What allowed us to complete the problems was our willingness to try something we were pretty sure would not work and then diagnose the non-working code to determine the necessary changes.

Flavors of Recursive Functions

After receiving help from an instructor, we found that return statements in recursive functions come in two flavors:

1. Return statements that rely only on the function call:

· return fib(n - 1) + fib(n - 2);
· return isEven(n - 2);
· return add(dec(x), inc(y));

2. Return statements that rely on the function call plus values outside of the recursive call to the function:

· return start + sum(start + 1, end);
· return y + multiply(x - 1, y);
· return start * product(start + 1, end);

Wednesday, November 16, 2016

DeMorgans Problem

// Write a function or that works like ||, but only uses ! and &&.

// Write a function OR that takes two Boolean values and returns 
// a Boolean value such that it is not true that both are false
// ... i.e., one or the other or both 

function OR(val1, val2) {
  return !(!val1 && !val2); 
}
function testDeMorgans(val1, val2) {
  return (val1 || val2) === OR(val1, val2);
}
testDeMorgans(true, true); // returns true meaning OR function === ||
testDeMorgans(true, false); 
testDeMorgans(false, false);