JavaScript Reference Guide
Table of Contents generated with DocToc
- Fundamentals
- Callbacks, Higher Order Functions and Closures
- Asynchronicity
- Classes and Prototypes (OOP)
- References
Fundamentals
- What is functional programming?
    - FP is about verbs, while OOP is about nouns
- Core tenant: pure functions don’t have side effects which in turn makes the code easier to test
 
- Core JavaScript engine has 2 main parts
    - Execution context
- Call stack
 
- An execution context is created to run the code of a function - has 2 parts:
    - Thread of execution
- Memory
 
- JS keeps track of what function is currently running, i.e. where’s the thread of execution using a Call Stack
- JavaScript has a single thread of execution
- Each function invocation gets its own new execution context
- Primitives are stored/passed by value and objects are stored/passed by reference
    var person = {}; person.name = "Mrs. White"; var who = person.name; who; // "Mrs. White" person.name = "Mr. White"; who; // Doesn't change; value remains "Mrs. White"
- Arrays are just objects, with some special utility methods and the length property
    var person = []; person.name = "Mrs. White"; var who = person.name; who; typeof person === "array"; // false; instead, Array.isArray() can be used to find out if an object is an array typeof person === "object"; // true person.push({age: 42}); // 0: {age: 42}, 1: {age: 54}, name: "Mrs. White" person.length; // 1
- Using variables to access object properties - the thing after the dot notation is coerced into a string literal, while
one can use variables in the [] notation.
    var person = []; var plea = "wouldShe"; person.name = "Mrs. White"; person[plea] = "I Would Never"; person; // {name: "Mrs. White", wouldShe: "I Would Never"}
- ES6 destructuring
    // variable declarations let [a, b] = [true, false]; a; // true b; // false let {a, b} = {b: 0, a: 1}; a; // 1 b; // 0
- Variables declared with lethave block scope while those withvarhave global scope
- for..inloop to iterate over keys of an object- var obj = {key1: 1, key2: 2}; for (var key in obj) { console.log(obj[key]); }
- for..ofloop to iterate over elements of array- let a = [1, 2, 3, 4, 5]; for (let num of a) { console.log(num); }
- Objects can have function in addition to attributes
    // ES5 var obj1 = { name: "foo", age: 19, speak: function() { console.log("ny name is ", this.name); } }; // ES6 var obj2 = { name: "foo", age: 19, speak() { console.log("ny name is ", this.name); } }
- Functions are just objects under the hood
- Spread operator, aka rest parameter syntax - like varargs in java
    var addAll = (...a) => { var sum = 0; for (var num of a) { sum = sum + num; } return sum; }; addAll(1, 2, 3, 4, 5); // 15
- Block scope can be create with let
    var fn = function () { var where = 'outer'; { let where = 'inner'; } console.log(where); // outer { var where = 'inner'; } console.log(where); // inner }; fn();
- varhoisting: a variable can be declared after it has been used- console.log(x); // undefined x = 5; console.log(x); // 5 var x = 6; console.log(x); // 6
- Variables and constants declared with letorconstare not hoisted
- Currying is a transform of functions that translates a function from callable as f(a, b, c) into a callable as 
f(a)(b)(c)
    function curry(f) { // curry(f) does the currying transform return function(a) { return function(b) { return f(a, b); }; }; } // usage function sum(a, b) { return a + b; } let curriedSum = curry(sum); curriedSum(1)(2); // 3
- Example of using reduceRun on JS Bin
Callbacks, Higher Order Functions and Closures
- Function that takes in a function as an argument or returns a function is called a higher-order function
- Function that is passed as an argument is called a callback
- ES6 arrow functions don’t have their own thisbinding like regular ES5 functionsconst user = { name: 'Anurag', sayHi: () => { console.log(`ES6 :: Hi, I'm ${this.name}`); }, sayHiAlt () { console.log(`ES5 :: Hi, I'm ${this.name}`); } }; user.sayHi(); // ES6 :: Hi, I'm user.sayHiAlt(); // ES5 :: Hi, I'm Anurag
- A closure is the combination of a function and the lexical environment (Persistent Lexical Scope Reference Data; colloquially referred to as the Clousure; referred to as backpack by Will Sentance) within which that function was declared Run on JS Bin
- Additional examples of closures and higher order functions
- JS is a lexically (statically) scoped language
    - The word “lexical” refers to the fact that lexical scoping uses the location where a variable is declared within the source code to determine where that variable is available
- Nested functions have access to variables declared in their outer scope
 
Asynchronicity
- JavaScript is:
    - Single threaded (one command runs at a time)
- Synchronously executed (each line is run in order the code appears)
 
- Features like timer (setTimeout), HTML DOM (document), network requests (xhr / fetch), console are not core JS 
features, instead are provided by the web browser / engine that runs JS
    - Example: setTimeoutis simply a facade function to call out functionality implemented by the runtime (say a web browser)
 
- Example: 
- JS has a concurrency model based on an event loop
    - Facade functions (formally known as runtime APIs) call out to the functionality provided by the runtime
- When the runtime has to pass a message back to JS execution context, it puts the message on a callback queue
(aka the task queue)
        - Each message has an associated function which gets called in order to handle the message
 
- The event loop continuously evaluates the state of the call stack and global execution context and if there is nothing to process, picks a pending message (if any) from the callback queue and puts it on the call stack
- Once the message from the runtime reaches the callback (via the callback queue) it is executed following standard JS execution rules
 
- Asynchronicity examples
- ES6 introduced promises as an alternative to callbacks
- Promises are two-pronged facade functions that both:
    - Initiate background work in the runtime (ex: web browser)
- Return a placeholder object (promise) immediately in JavaScript
- Promise object has two properties
        - value: the property that holds whatever is returned from the runtime function invoked by the facade function (ex: fetch)
- onFulfilled: an array of functions to be auto-run with value passed as a param, once the value property get a value
- onError: an array of functions to be run when the promise is rejected with an error
 
 
- Unlike promises, callbacks are limited in capability as they can only initiate the background but don’t have a placeholder object that can be interrogated to know what’s happening with the background task
- When a promise is fulfilled, the function passed to the promise object using the thenmethod is pushed to the microtask queueconst futureData = fetch('http://something.com/somepath'); futureData.then((data) => console.log(data));
- Event loop prioritises the microtask queue over the callback (or task) queue
    function display(data) { console.log(data); } function printHello() { console.log("Hello"); } function blockFor300ms() { /* some computation, say an expensive for loop */ } setTimeout(printHello, 0); const futureData = fetch('https://twitter.com/anuragkapur/tweets/1'); // let's assume the http request completes in less than 300ms, i.e. the promise if fulfilled in less than 300ms futureData.then(display); blockFor300ms(); console.log("Me first!"); /* Though the printHello function enters the callback queue before the display function enters the microtask queue, the Event loop dequeues the display function and pushes it to the call stack before the printHello function Console output: Me first! My tweet text Hello */
Classes and Prototypes (OOP)
- Objects
    - Creating an empty object
        const user1 = {}; const user2 = Object.create(null);
 
- Creating an empty object
        
- Object.create() method creates a new object, using an existing object as the prototype of the newly created object
    const person = { isHuman: false, printIntroduction: function () { console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`); } }; const me = Object.create(person); me.name = "Matthew"; // "name" is a property set on "me", but not on "person" me.isHuman = true; // inherited properties can be overwritten me.printIntroduction(); // "My name is Matthew. Am I human? true"
- Properties and methods can be added to empty objects in the future
    user1.name = "Foo"; user1.score = 3; user1.increment = function () { user3.score ++; };Creating objects
Approach 1: Using a function
- 
    function userCreator(name, score) { const newUser = {}; newUser.mame = name; newUser.score = score; newUser.increment = function () { newUser.score ++; }; return newUser; } const user1 = userCreator("Foo", 3); const user2 = userCreator("Bar", 6); user1.increment(); // 4 user2.increment(); // 7
- Problem: Each time we create a new user we allocate memory for all our data and functions. But functions are just copies = memory wasted!
- Benefit: Simple and easy to reason about
Approach 2: Using the prototype chain
- 
    function userCreator(name, score) { const newUser = Object.create(userFunctionStore); newUser.mame = name; newUser.score = score; return newUser; } const userFunctionStore = { increment: function() {this.score++;}, login: function() {console.log("Logged In");} }; const user1 = userCreator("Foo", 3); const user2 = userCreator("Bar", 6); user1.increment(); // 4 user2.increment(); // 7
 
- All objects have a __proto__property by default which defaults linking to a big object -Object.prototype
- Benefit: function copies (incrementandlogin) are not duplicated in memory
- Nested function (ES5 syntax and not the ES6 arrow function syntax) defined inside an object’s method does not 
bind the thiskeyword to the object that the method binds to. However, nested ES6 functions, bind thethiskeyword to the lexical scope and thus behave differently, i.e.thiskeyword binds to the object defining the method containing the nested function. This is illustrated in the example below:const user = { name: "Foo", score: 3, increment1: function() { function add1() {this.score++;} // `this` does not bind to the `user` object, instead binds to the global object which doesn't // have property `score` defined on it add1(); return this.score; }, increment2: function() { function add1() {this.score++;} // calls add1 with this bound to the user object to have the desired effect of incrementing // score from 3 to 4 add1.call(this); return this.score; }, increment3: function() { const add1 = () => {this.score++;}; add1(); return this.score; } }; console.log(user.increment1()); // 3 console.log(user.increment1()); // 3 console.log(user.increment1()); // 3 console.log(user.increment2()); // 4 console.log(user.increment2()); // 5 console.log(user.increment2()); // 6 console.log(user.increment3()); // 7 console.log(user.increment3()); // 8 console.log(user.increment3()); // 9- This is different to using arrow functions to define object methods - when arrow function is used to define object
method, their thisbinds to the global scope and not the object. However, when arrow function is defined inside an object method (defined using thefunctionkeyword), the arrow function’sthisbinds to the object and not global scope
 
- This is different to using arrow functions to define object methods - when arrow function is used to define object
method, their 
Approach 3: The new keyword
- When we call the function that returns an object with a newin front it automate 2 things:- Create a new object
- Return the new object
 
- 
    function userCreator(name, score) { this.name = name; this.score = score; } // - arrow function won't do the job as its `this` will bind to the global context and not the object created by // userCreator. // - all functions in JS are also objects and have a prototype property which is initialised to an empty object userCreator.prototype.increment = function() { return ++this.score; }; const user1 = new userCreator("Foo", 5); console.log(user1.increment()); // 6
- It’s best practice to capitalise first letter of the function name that is meant to be used with the newkeyword- If the function userCreatorin example above is called without the new keyword it will end up adding propertiesnameandscoreto the global scope instead of creating a new object with those properties and returning it
 
- If the function 
Approach 4: The class syntactic sugar
- 
    class UserCreator { constructor(name, score) { this.name = name; this.score = score; } increment() { return ++this.score; } login() { console.log("logged-in"); } } const user1 = new UserCreator("Foo", 5); console.log(user1.increment()); // 6
- The classfeature works exactly like approach 3, but its just cleaner as there is no need to separately define the functions in the prototype property usingobject.prototype
- The above is strikingly similar to how classes (i.e. data + methods) work in other languages like Java
- Introduced in ES2015/ES6
References