Eloquent JavaScript
Eloquent JavaScript
INTRO
`half of 100 is ${100 / 2}` // → “half of 100 is 50”
- Template literal = string literal but with `` instead of “ ”
- Some operators are symbols, some are words
- Operators:
-
CH1
- There are 4 types of values: string, #, boolean, undefined
- You can type in their name ( true, null) or value (13, “abc))
- Operators:
- Binary operators: +, -, *, /, %
- String concatenator +
- comparison (==, !=, ===, !==, <, >, <=, >=),
- logic (&&, ||)
- unary operators (- to negate a number, ! to negate logically, and typeof to find a
value’s type)
- ternary operator (?:) to pick one of two values based on a third value
CHAPTER 2:
- Expression = A fragment of code that produces a value
- Expressions make up statements (like sentence fragments make up full sentences)
- 1; // is a statement that is just a single expression then a (;)
- Side effects of statements = effects that ‘leave an impression on the world’ (i.e.
produce a value on the screen
- !false; //this will give us ‘true’, and then be thrown out, leaving no
impression on the world, so it’s useless code b/c nothing observable
happens
- You can define/assign multiple variables in the same line
- let one = 1, two = 2;
- console.log(one + two);
- // → 3
- Words JavaScript understands: (AKA reserved words; you can’t use for variable names)
- break case catch class const continue debugger default delete do else enum
export extends false finally for function if implements import interface in
instanceof let new package private protected public return static super switch this
throw true try typeof var void while with yield
- Environment = collection of bindings and their values that exist at a given time
- Executing a function = invoking/applying/calling
- console.log function() = executes that function
- Writes out response in hidden console if using browser
- You can open this by pressing “F12” or COMMAND-OPTION-1 on Macs
- Or search thru menus for something called “developer tools”
- Console is a binding, and log is a property
- console.log(Math.max(2, 4)); // → 4
CONTROL FLOW
- When program has more than 1 statement, it executes the statements in order (top to
bottom, left to right)
- Functions()
- Number() = converts values to numbers (i.e. converts string to #)
- String() = converts values to string (i.e. converts a number to a string value)
- Boolean() = converts values to boolean
- Number.isNaN() = returns true only if (#) is NaN
- !Number.isNan() = returns true only if (#) is a #
- {} called braces
- They link any amount of statements into one “block”
CONDITIONAL EXECUTION
- Not all programs are straight roads. We can write code with a branching road, then the
program takes one of the multiple options of roads. It makes the decision of which road
to take based on the situation at hand
- Created using “if” statements: the code only executes the “then” statement IF the
conditional statement is true
- “If, else” codes for telling program what to do if the statement is false
CHAPTER 3
FUNCTIONS
- Defines new vocab
- Structures larger programs
- Reduces repetition
- Associates names w subprograms
- Isolates subprograms
DEFINING A FUNCTION
- Like a regular binding, but the value of the binding is the function
- const square = function(x) {
- return x * x;
- };
-
- console.log(square(12));
- // → 144
- //second function below
- const makeNoise = function() {
- console.log("Pling!");
- };
-
- makeNoise(); // → Pling!
- // this code doesn’t have parameters and its result is “undefined” and is a
byproduct of the function
BINDINGS AND SCOPE
- Bindings defined outside of a function are global in scope
- Bindings defined inside a function are local in scope
- Let and const bindings are local to the block they’re declared in
- I.e. if you declare variable with const inside a loop, code before/after that loop
cannot see it
- Var keyword is global if outside a function
- Var is considered old-style, pre-2015 JavaScript
- Local > global for priority
- const halve = function(n) {
- return n / 2;
- };
-
- let n = 10;
- console.log(halve(100));
- // → 50
- console.log(n);
- // → 10
NESTED SCOPE
- Blocks and functions can nest inside other blocks and functions
- This creates multiple degrees of “locality”
- All scopes can see the global scope
- Local scopes can see the local scope one level up
- I.e. if there’s a loop inside a function, the loop can see the function’s local
bindings
- “Lexical scoping”
FUNCTIONS AS VALUES
- let launchMissiles = function() {
- missileSystem.launch("now");
- };
- if (safeMode) {
- launchMissiles = function() {/* do nothing */};
- }
- //launchMissiles was reassigned to do nothing in the if statement
- //launchMissiles is the name of the function, and can be used as a value in other
functions etc as a stand-in for the value “now”.
DECLARATION NOTATION
- Shortcut to create a function
- function square(x) {
- return x * x;
- }//this is a function declaration
- As opposed to this:
- const square = function(x) {
- return x * x;
- };
- console.log(square(12));
- // → 144
- They both do the same thing, but written differently
- console.log("The future says:", future());
-
- function future() {
- return "You'll never have flying cars";
- }
- You can define a function AFTER you use it bc the code always orders the
function at the top of its scope
ARROW FUNCTIONS
- A type of function notation used instead of “function” keyword
- const power = (base, exponent) => {
- let result = 1;
- for (let count = 0; count < exponent; count++) {
- result *= base;
- }
- return result;
- };
- //arrow is between function parameters and function body
- //arrow means this input (parameters) produces this result (body)
- const square1 = (x) => { return x * x; };
- const square2 = x => x * x;
- //square1 =square2, just written differently
- When arrow function has no parameters, () are empty
- const horn = () => {
- console.log("Toot");
- };
- Pretty much same as function keyword, just less wordy
THE CALL STACK
- function greet(who) {
- console.log("Hello " + who);
- }
- greet("Harry");
- console.log("Bye");
- //returns “Hello Harry
- //Bye”
- The function is called, then it finishes
- The order the function goes in (calls, switches to next console.log command etc) is
called “call stack”
- Every time function is called, the current context is stored on top of the stack
- When a function returns, it is removed from stack
- Storing the stack requires memory on the computer
- If the stack is too big and the comp runs out of memory, it’ll say “out of stack space” or
“too much recursion”
- If you accidentally create an infinite loop, you will run out of stack space or “blow the
stack”
- //below code creates infinite loop
- function chicken() {
- return egg();
- }
- function egg() {
- return chicken();
- }
- console.log(chicken() + " came first.");
- // → ??
OPTIONAL ARGUMENTS
- function minus(a, b) {
- if (b === undefined) return -a;
- else return a - b;
- }
-
- console.log(minus(10));
- // → -10
- console.log(minus(10, 5));
- // → 5
- If the # of given parameters != # of parameters in function, it can still work
- The code will just use the first parameters and ignore the rest, or assign
“undefined” to left out parameters
- function power(base, exponent = 2) {
- let result = 1;
- for (let count = 0; count < exponent; count++) {
- result *= base;
- }
- return result;
- }
-
- console.log(power(4));
- // → 16
- console.log(power(2, 6));
- // → 64
- //writing the parameter as “exponent = 2” makes the exponent parameter
optional, and if not given, then defaulting it to the value 2
CLOSURE
- Local bindings are recreated every time a function is called
- function wrapValue(n) {
- let local = n;
- return () => local;
- }
-
- let wrap1 = wrapValue(1);
- let wrap2 = wrapValue(2);
- console.log(wrap1());
- // → 1
- console.log(wrap2());
- // → 2
- //this code works fine, just like you’d expect
- //using empty parenthesis = to call the function, so “wrap1()” is calling the return function
- It shows that local bindings are made anew for every call; different calls can’t trample
over one another
- closure= being able to reference a specific instance of a local binding in an enclosing
scope
- Function values contain:
- Code body
- Environment in which they were created (not the environ in which they were
called)
- function multiplier(factor) {
- return number => number * factor;
- }
-
- let twice = multiplier(2);
- console.log(twice(5));
- // → 10
- //In the example, multiplier is called and creates an environment in which its factor
parameter is bound to 2. The function value it returns, which is stored in twice,
remembers this environment. So when that is called, it multiplies its argument by 2.
RECURSION
- Recursion = A function that calls itself
- If it calls itself too often, the stack will overflow
- Recursion is slower/more expensive than a simple loop b/c recursion will call the function
multiple times
- It’s a Q of speed vs elegance (machine-friendly vs human-friendly)
- Programmer has to decide what code is easy enough for human to read vs how
much space/time it takes up in the computer
- Rule of thumb= start by writing easy to read code, then improve if necessary
- function findSolution(target) {
- function find(current, history) {
- if (current == target) {
- return history;
- } else if (current > target) {
- return null;
- } else {
- return find(current + 5, `(${history} + 5)`) ||
- find(current * 3, `(${history} * 3)`);
- }
- }
- return find(1, "1");
- }
-
- console.log(findSolution(24));
- // → (((1 * 3) + 5) * 3)
- If we try to find findSolution(13), here’s what the computer does:
- find(1, "1")
- find(6, "(1 + 5)")
- find(11, "((1 + 5) + 5)")
- find(16, "(((1 + 5) + 5) + 5)")
- too big
- find(33, "(((1 + 5) + 5) * 3)")
- too big
- find(18, "((1 + 5) * 3)")
- too big
- find(3, "(1 * 3)")
- find(8, "((1 * 3) + 5)")
- find(13, "(((1 * 3) + 5) + 5)")
- found!
GROWING FUNCTIONS
- There are 2 ways for functions to be introduced
- 1: If you find yourself writing similar code a lot, you make that repeated code into
a function that you can re-call over and over
- 2: you realize you need some functionality that you haven’t written yet, and you
make a new function
- Resist urge to add cleverness to your code: it’s needlessly hard to read
- Resist urge to write general “framework” for every bit of functionality you come across,
bc it’s too much work
- Try to make it as easy for the next coder to understand as possible
CHAPTER 4
DATA STRUCTURES: OBJECTS AND ARRAYS
- Think of the index as the amount of items to skip, counting from the start of the array.
- Math.max = we access the prop named “max” in the Math object
- All javascript values have properties
- Except “null” and “undefined”
- If you know the name of prop you want is “color”, use value.color
- If you want to extract prop named by value held in binding i, use value[i]
- Prop names are strings
- Array
- An object
- Elements in array are properties (numbers are prop names)
- Property names are strings
- To find how many elements in array, use array.length (or array[“length”])
- array.push() is a method
- Array.length //tells us how many elements in array
-
- String
- Every string has a toUpperCase and toLowerCase prop
- These are functions called “methods” of the value they belong to
- Aka, “toUpperCase is a method of a string
- let doh = "Doh";
- console.log(typeof doh.toUpperCase);
- // → function
- console.log(doh.toUpperCase());
- // → DOH
- In operator tells you whether that object has a prop with that name
- let anObject = {left: 1, right: 2};
- console.log(anObject.left);
- // → 1
- delete anObject.left;
- console.log(anObject.left);
- // → undefined
- console.log("left" in anObject);
- // → false
- console.log("right" in anObject);
- // → true
- Delete method will remove prop, but undefined property will return true
- Object.keys function = finds out what prop names of the object tree
- console.log(Object.keys({x: 0, y: 0, z: 2}));
- // → ["x", "y", "z"]
- Object.assign function copies all props from one object into another
- let objectA = {a: 1, b: 2};
- Object.assign(objectA, {b: 3, c: 4});
- console.log(objectA);
- // → {a: 1, b: 3, c: 4}
- Mutability
- let object1 = {value: 10};
- let object2 = object1;
- let object3 = {value: 10};
-
- console.log(object1 == object2);
- // → true
- console.log(object1 == object3);
- // → false
- If you change object1, it does not change object3
- Correlation is a measure of dependence between statistical variables
- **statistical variable does not equate to a programming variable
- Correlation expressed as number -1 to +1
- -1 = inversely related (if one is true, the other is false)
- 0 = no relation
- +1 = positively correlated (if you know one, you know the other)
- phi coefficient (ϕ) used to compute measure of correlation btw 2 booleans
- This is a formula
- The input of the formula is a frequency table containing # of
different combos of 2 variables that were observed
- Output = number btw (-1) and (+1) that describes correlation
- If the coefficient = 0.06 for example, there is a very small relation
btw the 2 variables
ARRAYOLOGY
- For array loops, old way of writing loop:
- for (let i = 0; i < JOURNAL.length; i++) {
- let entry = JOURNAL[i];
- // Do something with entry
- }
- BETTER WAY OF WRITING LOOP:
- for (let entry of JOURNAL) {
- console.log(`${entry.events.length} events.`);
- }
- Used for strings and arrays
- When a for loop looks like this, with the word ‘of’ after a variable
definition, it will loop over the elements of the value given after ‘of’.
- Indexof = method to search thru array for specific value
- Returns index where specific value was found or (-1) if it was not found
- lastIndexOf = performs indexOf but starts searching from end of array
- Can take optional 2nd argument to tell method where to start searching from
- console.log([1, 2, 3, 2, 1].indexOf(2));
- // → 1
- console.log([1, 2, 3, 2, 1].lastIndexOf(2));
- // → 3
-
- Slice method
- takes start and end indices and returns an array that has only the elements
between them. The start index is inclusive, the end index exclusive.
- console.log([0, 1, 2, 3, 4].slice(2, 4));
- // → [2, 3]
- console.log([0, 1, 2, 3, 4].slice(2));
- // → [2, 3, 4]
-
- When the end index is not given, slice will take all of the elements after the start
index. You can also omit the start index to copy the entire array.
- Concat method
- Glues arrays together to create a new array (similar to + operator for strings)
- If you pass concat an argument that is not an array, that value will be added to
the new array as if it were a one-element array
- function remove(array, index) {
- return array.slice(0, index)
- .concat(array.slice(index + 1));
- }
- console.log(remove(["a", "b", "c", "d", "e"],
2));
- // → ["a", "b", "d", "e"]
- Strings and other properties
- You cannot add new properties to strings
- String, number, and Booleans are not objects. They are immutable.
- Strings have built-in methods:
- console.log("coconuts".slice(4, 7));
- // → nut
- console.log("coconut".indexOf("u"));
- // → 5
-
- console.log("one two three".indexOf("ee"));
- // → 11
-
- Trim method removes whitespace (spaces, newlines, tabs, and similar
characters) from the start and end of a string.
- console.log(" okay \n ".trim());
- // → okay
-
- padStart method: takes the desired length and padding character as
arguments.
- console.log(String(6).padStart(3,
"0"));
- // → 006
- Split method
- let sentence = "Secretarybirds
specialize in stomping";
- let words = sentence.split(" ");
- console.log(words);
- // → ["Secretarybirds", "specialize",
"in", "stomping"]
-
- Join method
- console.log(words.join(". "));
- // → Secretarybirds. specialize. in.
stomping
-
- Repeat method
- console.log("LA".repeat(3));
- // → LALALA
- let string = "abc";
- console.log(string.length);
- // → 3
- console.log(string[1]);
- // → b
- REST PARAMETERS:
- For a function to accept any number of parameters, its useful
- To do this: write “...” before the last parameter
- function max(...numbers) {
- let result = -Infinity;
- for (let number of numbers) {
- if (number > result) result =
number;
- }
- return result;
- }
- console.log(max(4, 1, 9, -2));
- // → 9
-
- You can use the … to call functions also:
- let numbers = [5, 1, 7];
- console.log(max(...numbers));
- // → 7
- //this spreads out the array into the function as separate elements,
instead of 1 element
- You can also do this:
- max(9, ...numbers, 2)
- You can also use … to spread an array into another array
- let words = ["never", "fully"];
- console.log(["will", ...words,
"understand"]);
- // → ["will", "never", "fully",
"understand"]
-
THE MATH OBJECT
- The Math object contains functions
- Math is somewhat useless as a value, unless it’s used as a “namespace” so all
the functions and values don’t have to have global bindings (b/c too many global
bindings pollutes the namespace)
- **the more names that have been used already, the more likely you are to
accidentally overwrite a previously used name
- ***Javascript only warns of overwriting a variable for let and const, NOT
for var or function
- Trig: the Math function has functions for: sin, cos, tan and their inverses: asin,
acos, atan
- Math.pi = 3.14… rounded to terminating digit
- *typically in Javascript, you write the names of constant values in CAPS
- Math.random= function that gets random-ish number between 0-1 (includes 0,
excludes 1)
- Uses hidden, complex algorithm to produce a value that seems random to
humans
- To get a whole#:
- console.log(Math.floor(Math.random() *
10));
- // → 2
- //this can produce any number 0-9
- Math.ceil rounds up the value
- Math.round rounds to nearest whole #
- Math.abs gives absolute number of value (turns neg into pos)
DESTRUCTURING
Making the phi coefficient function more succinct:
- Before:
- function phi(table) {
- return (table[3] * table[0] - table[2] *
table[1]) /
- Math.sqrt((table[2] + table[3]) *
- (table[0] + table[1]) *
- (table[1] + table[3]) *
- (table[0] + table[2]));
- }
-
- After:
- function phi([n00, n01, n10, n11]) {
- return (n11 * n00 - n10 * n01) /
- Math.sqrt((n10 + n11) * (n00 + n01) *
- (n01 + n11) * (n00 + n10));
- }
-
- This works for variables let, var, and const
- You can do the same for objects, using {braces} instead of [square brackets]
- let {name} = {name: "Faraji", age: 23};
- console.log(name);
- // → Faraji
-
- *you cannot destructure a null or undefined value