209 lines
8.2 KiB
Markdown
209 lines
8.2 KiB
Markdown
|
# 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`
|