From 5ea4e5c80e4a775d29608c8bedad125c77d811ad Mon Sep 17 00:00:00 2001 From: JasonHomeWorkstationUbuntu Date: Thu, 17 Dec 2020 01:50:38 +0000 Subject: [PATCH] Finished Chap01 --- .devcontainer/devcontainer.json | 2 +- notes/chap1_introduction_to_javascript.md | 209 ++++++++++++++++++++++ src/chap1/charfreq.js | 93 ++++++++++ src/chap1/hello.js | 1 + 4 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 notes/chap1_introduction_to_javascript.md create mode 100644 src/chap1/charfreq.js create mode 100644 src/chap1/hello.js diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index af2ee4b..e67287c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -17,7 +17,7 @@ ], // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], + "forwardPorts": [3000], // Use 'postCreateCommand' to run commands after the container is created. // "postCreateCommand": "yarn install", diff --git a/notes/chap1_introduction_to_javascript.md b/notes/chap1_introduction_to_javascript.md new file mode 100644 index 0000000..7bc4b78 --- /dev/null +++ b/notes/chap1_introduction_to_javascript.md @@ -0,0 +1,209 @@ +# Chapter 1. Introduction to JavaScript + +* JavaScript is nothing related to Java. +* JS has grown from pure scripting-language to a robust general-purpose language (like C, C++) + +JS & host environment: +* Core JS defines minimal API (numbers, text, etc). +* Input/Output, advanced feature belongs to "host environment" in which JS is embedded. E.g. of host env + * Web browser: original host env + * Input to JS: mouse click, keyboard + * Output from JS: display HTML & CSS + * Node: JS can access entire OS, so JS can read/write files as well. + +## 1.1 Exploring JavaScript + +To test JS interactly, methods available: +1. JS interpretor in web browser as **web developer tools (F12)**, select **Console** +2. Download & Install node.js and type `node` to activate interactive JS session. + 1. I prefer to use [VSCode Remote Development Container Images for Node.js](https://github.com/microsoft/vscode-dev-containers/tree/master/containers/javascript-node), which can be set directly using `.devcontainer.json` file + +## 1.2 Hello World + +Run JS codes, 2 methods: +1. Copy/Paste codes to JS console +2. (Docker preference) Save codes to a file `.js`, run file of JavaScript code with Node `node snippet.js` + +## 1.3 A Tour of JS + +Quick introduction to JS using code e.g. + +### Basic syntax + +* Comments +* Variable declaration +* Assigning value +* Data types + +```js +// Anything following double slashes is an English-language comment. +// Read the comments carefully: they explain the JavaScript code. + +// A variable is a symbolic name for a value. +// Variables are declared with the let keyword: +let x; // Declare a variable named x. + +// Values can be assigned to variables with an = sign +x = 0; // Now the variable x has the value 0 +x // => 0: A variable evaluates to its value. + +// JavaScript supports several types of values +x = 1; // Numbers. +x = 0.01; // Numbers can be integers or reals. +x = "hello world"; // Strings of text in quotation marks. +x = 'JavaScript'; // Single quote marks also delimit strings. +x = true; // A Boolean value. +x = false; // The other Boolean value. +x = null; // Null is a special value that means "no value." +x = undefined; // Undefined is another special value like null. +``` + +* Objects +* Arrays + +```js +// JavaScript's most important datatype is the object. +// An object is a collection of name/value pairs, or a string to value map. +let book = { // Objects are enclosed in curly braces. + topic: "JavaScript", // The property "topic" has value "JavaScript." + edition: 7 // The property "edition" has value 7 +}; // The curly brace marks the end of the object. + +// Access the properties of an object with . or []: +book.topic // => "JavaScript" +book["edition"] // => 7: another way to access property values. +book.author = "Flanagan"; // Create new properties by assignment. +book.contents = {}; // {} is an empty object with no properties. + +// Conditionally access properties with ?. (ES2020): +book.contents?.ch01?.sect1 // => undefined: book.contents has no ch01 property. + +// JavaScript also supports arrays (numerically indexed lists) of values: +let primes = [2, 3, 5, 7]; // An array of 4 values, delimited with [ and ]. +primes[0] // => 2: the first element (index 0) of the array. +primes.length // => 4: how many elements in the array. +primes[primes.length-1] // => 7: the last element of the array. +primes[4] = 9; // Add a new element by assignment. +primes[4] = 11; // Or alter an existing element by assignment. +let empty = []; // [] is an empty array with no elements. +empty.length // => 0 + +// Arrays and objects can hold other arrays and objects: +let points = [ // An array with 2 elements. + {x: 0, y: 0}, // Each element is an object. + {x: 1, y: 1} +]; +let data = { // An object with 2 properties + trial1: [[1,2], [3,4]], // The value of each property is an array. + trial2: [[2,3], [4,5]] // The elements of the arrays are arrays. +}; +``` + +Comment Syntax in code e.g. +* `=>` shows value produced by code +* `// !` code on the line throws an exception + +### Expression vs. Statement + +* **Expression** used by JS to evaluate and produce a value, but don't do anything +* **Statement** don't have a value but alter the state of program. e.g. variable declaration & assignment statement + +## 1.4 Example: Charater Frequency Histograms + +```js +/** + * This Node program reads text from standard input, computes the frequency + * of each letter in that text, and displays a histogram of the most + * frequently used characters. It requires Node 12 or higher to run. + * + * In a Unix-type environment you can invoke the program like this: + * node charfreq.js < corpus.txt + */ + +// This class extends Map so that the get() method returns the specified +// value instead of null when the key is not in the map +class DefaultMap extends Map { + constructor(defaultValue) { + super(); // Invoke superclass constructor + this.defaultValue = defaultValue; // Remember the default value + } + + get(key) { + if (this.has(key)) { // If the key is already in the map + return super.get(key); // return its value from superclass. + } + else { + return this.defaultValue; // Otherwise return the default value + } + } +} + +// This class computes and displays letter frequency histograms +class Histogram { + constructor() { + this.letterCounts = new DefaultMap(0); // Map from letters to counts + this.totalLetters = 0; // How many letters in all + } + + // This function updates the histogram with the letters of text. + add(text) { + // Remove whitespace from the text, and convert to upper case + text = text.replace(/\s/g, "").toUpperCase(); + + // Now loop through the characters of the text + for(let character of text) { + let count = this.letterCounts.get(character); // Get old count + this.letterCounts.set(character, count+1); // Increment it + this.totalLetters++; + } + } + + // Convert the histogram to a string that displays an ASCII graphic + toString() { + // Convert the Map to an array of [key,value] arrays + let entries = [...this.letterCounts]; + + // Sort the array by count, then alphabetically + entries.sort((a,b) => { // A function to define sort order. + if (a[1] === b[1]) { // If the counts are the same + return a[0] < b[0] ? -1 : 1; // sort alphabetically. + } else { // If the counts differ + return b[1] - a[1]; // sort by largest count. + } + }); + + // Convert the counts to percentages + for(let entry of entries) { + entry[1] = entry[1] / this.totalLetters*100; + } + + // Drop any entries less than 1% + entries = entries.filter(entry => entry[1] >= 1); + + // Now convert each entry to a line of text + let lines = entries.map( + ([l,n]) => `${l}: ${"#".repeat(Math.round(n))} ${n.toFixed(2)}%` + ); + // And return the concatenated lines, separated by newline characters. + return lines.join("\n"); + } +} + +// This async (Promise-returning) function creates a Histogram object, +// asynchronously reads chunks of text from standard input, and adds those chunks to +// the histogram. When it reaches the end of the stream, it returns this histogram +async function histogramFromStdin() { + process.stdin.setEncoding("utf-8"); // Read Unicode strings, not bytes + let histogram = new Histogram(); + for await (let chunk of process.stdin) { + histogram.add(chunk); + } + return histogram; +} + +// This one final line of code is the main body of the program. +// It makes a Histogram object from standard input, then prints the histogram. +histogramFromStdin().then(histogram => { console.log(histogram.toString()); }); +``` + +Running this program using command in Docker `node charfreq.js < charfreq.js` \ No newline at end of file diff --git a/src/chap1/charfreq.js b/src/chap1/charfreq.js new file mode 100644 index 0000000..5d99684 --- /dev/null +++ b/src/chap1/charfreq.js @@ -0,0 +1,93 @@ +/** + * This Node program reads text from standard input, computes the frequency + * of each letter in that text, and displays a histogram of the most + * frequently used characters. It requires Node 12 or higher to run. + * + * In a Unix-type environment you can invoke the program like this: + * node charfreq.js < corpus.txt + */ + +// This class extends Map so that the get() method returns the specified +// value instead of null when the key is not in the map +class DefaultMap extends Map { + constructor(defaultValue) { + super(); // Invoke superclass constructor + this.defaultValue = defaultValue; // Remember the default value + } + + get(key) { + if (this.has(key)) { // If the key is already in the map + return super.get(key); // return its value from superclass. + } + else { + return this.defaultValue; // Otherwise return the default value + } + } +} + +// This class computes and displays letter frequency histograms +class Histogram { + constructor() { + this.letterCounts = new DefaultMap(0); // Map from letters to counts + this.totalLetters = 0; // How many letters in all + } + + // This function updates the histogram with the letters of text. + add(text) { + // Remove whitespace from the text, and convert to upper case + text = text.replace(/\s/g, "").toUpperCase(); + + // Now loop through the characters of the text + for(let character of text) { + let count = this.letterCounts.get(character); // Get old count + this.letterCounts.set(character, count+1); // Increment it + this.totalLetters++; + } + } + + // Convert the histogram to a string that displays an ASCII graphic + toString() { + // Convert the Map to an array of [key,value] arrays + let entries = [...this.letterCounts]; + + // Sort the array by count, then alphabetically + entries.sort((a,b) => { // A function to define sort order. + if (a[1] === b[1]) { // If the counts are the same + return a[0] < b[0] ? -1 : 1; // sort alphabetically. + } else { // If the counts differ + return b[1] - a[1]; // sort by largest count. + } + }); + + // Convert the counts to percentages + for(let entry of entries) { + entry[1] = entry[1] / this.totalLetters*100; + } + + // Drop any entries less than 1% + entries = entries.filter(entry => entry[1] >= 1); + + // Now convert each entry to a line of text + let lines = entries.map( + ([l,n]) => `${l}: ${"#".repeat(Math.round(n))} ${n.toFixed(2)}%` + ); + // And return the concatenated lines, separated by newline characters. + return lines.join("\n"); + } +} + +// This async (Promise-returning) function creates a Histogram object, +// asynchronously reads chunks of text from standard input, and adds those chunks to +// the histogram. When it reaches the end of the stream, it returns this histogram +async function histogramFromStdin() { + process.stdin.setEncoding("utf-8"); // Read Unicode strings, not bytes + let histogram = new Histogram(); + for await (let chunk of process.stdin) { + histogram.add(chunk); + } + return histogram; +} + +// This one final line of code is the main body of the program. +// It makes a Histogram object from standard input, then prints the histogram. +histogramFromStdin().then(histogram => { console.log(histogram.toString()); }); \ No newline at end of file diff --git a/src/chap1/hello.js b/src/chap1/hello.js new file mode 100644 index 0000000..db79aa1 --- /dev/null +++ b/src/chap1/hello.js @@ -0,0 +1 @@ +console.log("Hello World!") \ No newline at end of file