JavaScript

Style

You should use lowerCamelCase for variables, properties and function names.

var myVarName = 'name';
var myFunctionName = function() {
  //some function
};

You should use UpperCamelCase for class names.

class MyClass {
  //class definition
}

You should use ' single quotes for strings unless you are writing in JSON.

var myString = 'my string';

Variables

You can define a new variable in Javascript using the var keyword.

var x = 5;

You can print out the name of a variable using the Javascript Object.keys and submitting the variable to the keys hash.

var myVar = 42
Object.keys({myVar})[0] // => 'myVar'

Undefined

An unassigned variable returns undefined.

var a; // => undefined

If you add a number undefined variable you will get the type NaN for “Not a Number”.

var a; // => undefined
a + 5; // => NaN

If you a add a string to an undefined variable you will get the word "undefined" as a string literal.

var a;
a + ""; // => 'undefined'

Constants

Constants are Javascripts immutable variables. They are defined using the keyword const.

const N = 204;
N = 300; //ERROR

Javascript are actually just constant references to variables. This means that you cannot change a primitive constant, but you can change the properties of an object constant. This changing principle goes for all types of objects including arrays, hashes etc.

const profile = { name:"Tatsuki", age:"59" };
// change the age property of the profile object
profile.age = "60";
// CANNOT change profile to point to a new object
profile = { name:"Ogawa", age:"18" }; //ERROR

The Global Object

The global object is an object on which all global variables for your script are defined. The global object is client side javascript specific, i.e. it is not a feature in node.js. In browser based javascript the default global object is window. At the top level scope, creating a new var will add it to the global object.

var spam = 'spam';
window.spam; // => 'spam'

Var vs Let

The let and var keywords are different ways of defining a variable in Javascript. The primary difference between them is their scoping and definition.

Scoping

The **var defined variable are scoped to the function they are declared in** whereas let defined variables are scoped to the block they are defined in and any blocks contained within that block.

If you try to use a let variable in a block with a scope outside of the one it was defined in you will get a ReferenceError.

{
  let spam = 'spam';
}
console.log(spam); // => ReferenceError

However if you define a var variable inside a block it will still be available outside of that block.

{
  var spam = 'spam';
}
console.log(spam) // => 'spam'

You can still access let variables from nested blocks.

function spamFunction() {
  let spam = 'spam';
  {
	console.log(spam); // => spam
  }
}

Furthermore var defined variables are NOT available outside of the function they were defined in.

function spamFunction() {
  var spam = 'spam';
}
console.log(spam) // => ReferenceError

Hoisting

Variables define with var are hoisted. This means that even before they are ever defined in the flow of execution of the code they are initialized with an undefined type meaning that they won’t throw an error if used before their definition.

function hoisting() {
  console.log(spam); // => undefined
  var spam = 'spam';
  console.log(spam); // => 'spam'
}

However calling a let variable before definition results in a `ReferenceError.

function hoisting() {
  console.log(spam); // => ReferenceError
  let spam = 'spam';
  console.log(spam); // => 'spam' (but never gets executed due to error above)
}

Global Object

At the top level scope var defined variables are added as properties of the global object, whereas let define variables are not.

var spam = 'spam';
let ham = 'ham';

console.log(window.spam); // => 'spam'
console.log(window.ham); // => undefined

Redeclaration

In strict mode you can redefine var variables however trying redefining a let variable in a single scope will result in a syntax error.

'use strict';
var spam = 'spam';
var spam = 'yam'; // spam is replaced

let ham = 'ham';
let ham = 'eggs'; // SyntaxError

Symbols

The Symbol() function is a primitive Javascript type that defines a unique identifier.

Conditionals

Javascript automatically coerces string and integer types when running a comparison, such that writing out one number an an integer 5 and writing string containing just the character '5' will be evaluated as true when compared.

if (5 == '5') // => true

You can stop integers and the string forms of integers being compared as true by using the strict equality operator ===. This operator simply does not perform any type conversion on its arguments.

if (5 === '5') // => false

The != inequality operator follows the same rule as the equality operator for type coercion. There is also a strict inequality that works like the strict equality operator.

if (5 != '5') // => false
if (5 !== '5') // => true

You can return the result of a conditional directly from a function by placing the conditional statement after a return

function isNotEqual(a, b) {
  return a !== b
}

Switch

To match multiple conditions use a switch statement. This allows to test a variable and match its value using a case block to execute a specific piece of code.

var myVar = 12;

switch (myVar) {
  case 12:
    console.log('it is twelve');
    break;
  case 13:
    console.log('it is thirteen');
    break;
}
// => it is twelve

Statements inside a switch block are executed from the first match until a break is encountered. This means, if you forget to add a break the code below, even though it does not match your condition will also be execute. As you can see from the example below the because the break statement is missing from the matched case statement of 12 the next block that matches 13 is also executed.

var myVar = 12;

switch (myVar) {
  case 12:
    console.log('it is twelve');
  case 13:
    console.log('it is thirteen');
    break;
}
// => 'it is twelve'
// => 'it is thirteen'

You can add a default return type to a switch block using the default keyword.

switch(n) {
  case 1:
    //some code
    break;
  // ...
  default:
    console.log('no value found');
    break;
}

You can describe the same output for multiple inputs by letting case blocks without keywords “cascade down”.

switch(n) {
  case 1:
  case 2:
  case 3:
    // do something
    break;
  case 4:
    // something else
    break;
}

Strings

You can place " double quotes directly into ' single quote strings.

var sampleText = 'She came in and said "Good Morning." to everyone.';

You can place " double quotes inside " double quotes by escaping them.

var sampleText = "She came in and said \"Good Morning.\" to everyone.";

You can use the += operator to concatenate and assign the string result.

var text = 'Some text.';
text += ' And some more text.'; // => 'Some text. And some more text.'

You can ** get the length of a string** using the string length function.

'Hello'.length; // => 5

The contents of strings are immutable. This immutability refers only to the actual string object NOT the reference to the string. In the example below you can see that trying to change a string character by index leaves the value of text unchanged because the string is immutable. However the text variable that points to the string IS mutable and can be reassigned to a new string object entirely.

var text = 'Bob';
text[0] = 'J'
text // => 'Bob' - string not changed
text = 'Job'
text // => 'Job' - text reassigned to a new immutable string

You can return a specific sub-string character of a string by appending [ ] square brackets to its end as if it were an array and placing the index of the character you want to output.

'Hello'[0]; // => 'H'

You can interpolate variables into a string by surrounding your string with back-ticks and using a ${ } symbol inside the string with the variable you want to interpolate placed between the curly brackets.

var name = 'Dec';
console.log(`My name is ${name}.`);

You cannot multiply strings in Javascript. For example, 'd' * 5 is not valid syntax for outputting 'ddddd', instead you should use the repeat method on a string to duplicate it. This returns the duplicated string.

// with var
var letter = 'd'
letter.repeat(5) // => 'ddddd'
// directly in a string
'd'.repeat(5) // => 'ddddd'

Arrays

You can access the content of multi dimensional arrays using two consecutive sets of [ ] square brackets.

var array = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];

array[1][0] // => 4

You can iterate through a range in a functional style by creating an array, filling it and then iterating.

Array(8).fill().map((_, i) => i * i)

Manipulating elements

You can add an element to the end of an array using the push function. You can add an element to the start of an array using the unshift function.

var array = [4, 5, 6];
array.push(7); // => [4, 5, 6, 7]
array.unshift(3); // =>[3, 4, 5, 6, 7]

You can remove an element from the end of an array using the pop function. You can remove an element from the start of an array using the shift function.

var array = [4, 5, 6];
array.pop(); // => [4, 5]
array.shift(); // => [5]

You can remove a specific item from an array by using the array filter function. This works in ES6 only. In the example below any item that is not equal to 4 is placed back into the array.

arr = [1, 2, 3, 4, 5];
arr = arr.filter(item => item !== 4); // => [1, 2, 3, 5]

You can easily push elements to and clone an array simultaneously by using spread syntax on a destructured array. The push function below takes a new item and an array, the it uses the ... spread syntax to take specify every element and then concatenates it with the item returning the new array.

const push = (item, array) => [...array, item]

You can easily unshift elements to and clone an array simultaneously by using the same syntax but swap the order in array construction.

const unshift = (item, array) => [item, ...array]

Map

The array map function actually passes 3 arguments to its function argument these are:

  1. the current value of a positional member of the array
  2. the current index of a positional member of the array
  3. the entire array

And, they are passed to the function argument in this order.

const write = x => console.log(x)

['a', 'b', 'c'].map(write)
// => a 0 ['a', 'b', 'c']
// => b 1 ['a', 'b', 'c']
// => c 2 ['a', 'b', 'c']

do … while loops

do ... while loops follow the structure of having a piece of code placed in a do block followed by a condition for executing that code multiple time in a while statement. Uniquely do ... while loops always execute once before their conditions is evaluated, because the condition is placed after the execution block. The basic definition syntax is:

let i = 0;
do {
  console.log(i);
  i++;
} while (i < 5);
// => 1 2 3 4 5

If you set i = 5 with the same code i will still be printed once because the while condition is not immediately evaluated.

let i = 5;
do {
  console.log(i);
  i++;
} while (i < 5);
// => 5

For … of

You can iterate through a general iteratable Javascript object, such as arrays, using the for and of keywords. By defining a set of elements in the iteratable object to loop through. The individual values inside the do not have to be defined as const, but can use any variable type if they need to be mutable.

let arr = [1, 2, 3, 4, 5];

for(const n in arr) {
  console.log(n);
}
// compressed for formatting
// => 1 2 3 4 5

Iterables

Iterables are a generalised implementation in Javascript that allow any object to be used with the for ... of language iterator. This functionality is built into many native javascript objects, like Array or String, in the former case the elements stored in the array will be iterated over and in the latter the individual letters of the string will be iterated over.

As a programmer you may define a custom object which represents a list of information for which it would be useful to iterate over with for ... of. To do this you have to add a property to the object with the name Symbol.iterator to your object and bind that to a function that returns an object that can be used for iteration. When calling for ... of on the object in question that first thing that happens is that node attempts to look for the Symbol.iterator property on the object, if it doesn’t find it then the program will throw an is not iterable error. The example below shows the very basics of how you would start implementing a custom iterator on an object.

let counter = {}
counter[Symbol.iterator] = () => {
  // implement the iterator here
}

For the iterator to work the method that Symbol.iterator points to must return an object which implements the next method. The next method is called on each loop of the for ... of and represents the next item to be iterated on. In practice next returns a further object with the keys done and value, if this result object returns done = true then the loop exits otherwise it outputs the value portion of this object.

let counter = {
  from: 1,
  to: 5
}

counter[Symbol.iterator] = () => {
  
}

Map

You can ** construct an Array from an iterator** using the Array.from method.

Functions

You can define a function using the function keyword.

function myFunction(parameter) {
  console.log(parameter);
}

Javascript functions are treated just like regular variables. You can assign an un-named function to a var using = to name the function.

var myFunction = function() {
  return 'hello';
};

You can call a function by appending () to the end of the variable name that describes the function.

myFunction(); // => 'hello'

If you define a variable in a function without using the var keyword. Then the function variable will be in the global scope. The global variable is only assigned when the function is called. To limit variables to the local scope of the function the var keyword inside functions!

function myBadFunction() {
  globalVariable = 5;
}
globalVariable // => 5

function myBetterFunction() {
  var localVariable = 5;
}
localVariable // => undefined

Any variables defined in the main code are available in the function scope. If a local and global variable conflict then the local variable takes precedence.

var myVar = 5;
function myAdder() {
  return 10 + myVar;
}

myAdder(); // => 15

function conflict() {
  var myVar = 10;
  return 10 + myVar;
}

conflict(); // => 20

A function returns undefined if you do not add a return statement to it.

function myUndefined() {
  console.log('Return type is undefined');
}

myUndefined(); // => undefined
// => Return type is undefined.

Lexical Scoping

A function define within another function has access to the variables of that function. In the example below the eggs function has access to the ham variable because it is defined within the function scope. This is called lexical scoping and describes how the function eggs resolves the variable name ham as referring to the context in which it was define. This context is called the lexical environment of a function.

function spam() {
  var ham = 'ham';
  function eggs() { // define the eggs function
    console.log(ham);
  }
  eggs(); // call the eggs function
}
spam(); // => 'ham'

Closures

A closure refers to a situation in which the lexical environment of a function (i.e. the outer it was defined in) comes bundled with a reference to that function. In the example below, instead of all the eggs function within the spam function it is instead returned and assigned to the beans variable and then called. This is an example of a closure because even though the local ham variable that was defined inside the body of spam has been called and passed out of scope, beans as a copy of the inner function eggs keeps a reference to that variable and its value and can still return it as it were still contained within the lexical environment of the spam function.

function spam() {
  var ham = 'ham';
  function eggs() { // define the eggs function
    console.log(ham);
  }
  return eggs; // call the eggs function
}
var beans = spam();
beans(); // => 'ham'

You can uses closures to store lexical environments as a way of configuring functions. In the example below, the makeBreakfastFunction returns a function that simple concatenates its initial argument with an argument that is placed into the returned function. By assigning this return to a var we created a closure that remembers the state of main when it was created. Essentially we store the environment at the definition of the returned function without having to reference outside variables. Because closures allow to associate data with a function similarly to how you might associate data with functions in a class. They can be useful any time you have a class that would have some data and only a single function.

function makeBreakfastFunction(main) {
  return function(side) {
    return main + ' and ' side;
  };
}
var spamBreakfast = makeBreakfastFunction('spam');
var eggsBreakfast = makeBreakfastFunction('eggs');

console.log(spamBreakfast('beans'); // => 'spam and beans'
console.log(eegsBreakfast('beans'); // => 'eggs and beans'

The data inside a closures lexical environment is persistent across all instances of that closure. In the example below we create a closure with the count variable set to 0 and return a function add that adds one to the count. When we create a new incrementer from the counter function the count is initialised to 0 and then counts up every time the function object is called. If we create a new incrementer2 it resets the lexical environment for BOTH closures. They both start back at 0 and both closure objects will alter the lexical environment. They are tied to it together.

function  counter() {
  count = 0;
  function  add() {
    count += 1;
    console.log(count);
  }
  return  add;
  }
incrementer = counter();
incrementer(); // => 1
incrementer(); // => 2
incrementer2 = counter();
incrementer2(); // => 1
incrementer2(); // => 2
incrementer(); // => 3

When creating nested functions. Each function has access to the closure scope of all enclosing functions. In the example below each anonymous function has access to all the function scope above it. the function with argument d has access to the function of scope of the top level add function and every function in between.

function add(a) {
  return function(b) {
    return function(c) {
      // function scope
      return function(d) {
	    // local scope
        return a + b + c + d;
      }
    }
  }
}
add(1)(2)(3)(4); // => 10

Callbacks

A callback is a function that is called somewhere in another function when passed as an argument and usually executes once the calling functions body has finished executing.

// caller function that takes a function as an argument and calls it
function caller(callback) {
  callback()
}

caller(function() {
  console.log('hello')
})
// => 'hello'

IIFE

An IIFE or immediately invoked function expression involves containing a function inside a set of grouping operator parentheses ( ) followed by a further set of execution parentheses ( ). The function below is immediately returned defined and executed with its return value.

(function() { return 'hello' })() // => 'hello'

You can submit an argument to the enclosing IIFE by placing in the execution parentheses at the end of the code.

(function(arg) { return arg })('hello') // => 'hello'

You can define IIFEs with function names, however the name will not be stored.

(function sayHello() { return 'hello' })() // => 'hello'

You can use IIFE to contain variables to avoid the global scope becoming polluted. In the example below we may want to work with a var and have actions using the var execute immediately but keep the var names separate from the scope in which the code is executing in.

(function antiPollution() {
  var message = 'hello'
  return message
})() // => 'hello'
// message => undefined

You can add IIFE defined function to a particular scope while maintaining their context using closures. In the example below, the context is some context or object that we want the sayHello method to be available in, we then add it as a variable to the context. This sayHello method can now retrieve the message variable, but the message itself is not in scope. This allows us to mediate what is accessible within particular scopes to particular methods.

(function(context) {
  var message = 'hello'
  function sayHello() {
    return message
  }
  context.sayHello = sayHello
})(this)

message // => undefined
sayHello() // => 'hello'

Arrow Functions

An arrow function allows you condense the syntax for defining anonymous functions by omitting the function keyword and using a => hash rocket arrow instead. Arrow functions are anonymous by default, so to use them you need to assign them to a variable. Arrow functions also have the effect of preserving the this context that the function was defined in.

let myFunction = () => {
  return 'hello'
}

You can condense arrow functions to one line and omit curly braces and return statements associated with them.

let myFunction = () => 'hello'

You can include argument in your arrow functions by placing it between the brackets.

let myFunction = (arg) => arg * 2

You can also use arrow functions as callbacks in other functions.

setTimeout(() => {
  console.log('hello')
}, 500)

Spread Arguments

You can define functions that take a arbitrary length list of arguments (similar to splat arguments in other languages) by using the ... triple period spread syntax in the function’s argument list. The variable designated as the list of arguments will be converted into an iterable object.

const doubleList = (...n) => n.map(x => x * 2)

JSON

JSON is a format for serializing javascript objects. You can parse a JSON string into a javascript object using the JSON.parse method.

const json_string = '{"result":true, "count":42}';
const json_object = JSON.parse(json_string);
json_object.result // => true
json_object.count // => 42

You can convert a javascript object to JSON to be sent via an API call or other method by using the JSON.stringify() method.

let myObject = {name: 'dec', age: 28}
JSON.stringify(myObject) // => "{"name":"dec", "age":"28"}"

Classes

There are two ways to define classes in Javascript. There is an older ES5 standard that uses the function keyword and the newer ES6 standard that uses the new Class keyword.

ES5

To define instance variables in ES5 use the this keyword inside the class definition.

// ES5 class definition
var Antelope = function(name) {
  this.name = name;
};

You can define methods outside of the class body using the pototype field to add methods to the class.

Antelope.prototype.myFunction = function() {
  return 'My name is ' + this.name
};

ES6

To define instance variables in ES5 use the constructor block with the initialisation arguments and assignments placed inside.

// ES6 class definition
class Antelope {
  constructor(name) {
    this.name = name;
  }
}

You can define class and instance methods inside the body of the class using the ES6 standard. You can also use the prototype syntax to add methods to ES6 classes.

class Antelope {
  constructor(name) {
    this.name = name;
  }

  myFunction() {
    return 'My name is ' + this.name
  }
}

Both Standards

You can create a new instance of a class using the new keyword followed by the object.

// this new definition works for both ES5 and ES6
var antelope = new Antelope('Jonathan');

Class and instance variables are public by default. For example we can directly access and change the name parameter of an Antelope class instance object.

antelope.name = 'Mark';
antelope.myFunction(); // => 'My name is Mark.'

Prototype

Functions added to classes using prototype are separate from functions added within a class. If you define a functional class (ES5 syntax) with methods contained within, these methods will indeed be duplicated on each new object that you create from that class, however, they will be separate pieces within memory. However if you create functions on the prototype property of a class then that method will exist in one place, and class instances that refer to that prototype function will simply reference it.

In the example below, when creating a new instance of Dog the sayName function will be copied for each instance.

function Dog(name) {
  this.name = name;
  
  this.sayName = function() {
    console.log(this.name);
  }
}

However, if the sayName function is added to Dog using prototype then every instance of Dog will share the same function.

function Dog(name) {
  this.name = name;
}

Dog.prototype.sayName = function() {
  console.log(this.name);
}

When overwriting a function defined in both the class definition and prototype, the class definition version of the function takes precedence.

function Dog(name) {
  this.name = name;
  
  this.sayName = function() {
    console.log(this.name);
  }
}

Dog.prototype.sayName = function() {
  console.log('woof');
}

let dog = new Dog('Banjo');
dog.sayName(); // => 'Banjo'

Using prototype is also useful for testing because it allows you to mock an entire function definition on a class rather than a function definition of a specific instance. For example, if Dog had an injected dependency of Bark and called sound on Bark this could be mocked in tests easily by simply creating a prototype object for Bark in our test suite. The Dog class would take in a new instance of Bark.

function Dog(name, bark) {
  this.name = name;
  this.bark = bark;
}

Dog.prototype.sound = function() {
  console.log(this.bark.sound());
}

Then the associated test could create its own empty mock of Bark. So that there are no errors when bark.sound() is called during testing and our dependency has been mocked.

fakeBark = function() {}
fakeBark.prototype.sound = function() {}

Class Methods

You can create the equivalent of a class method in javascript by adding a method as a parameter directly to the a class object. You have to define the class methods outside of the class body.

class MyClass {
  constructor() {}
}

MyClass.someClassMethod = function() { console.log('hello') }

// call class method
MyClass.someClassMethod() // => 'hello'

Class Type

You can return the name of the type of an object (similar to returning the class type that an object is) by using the constructor.name property of an object.

myString = 'hello';
myString.constructor.name // => name

Scope

This

Javascript’s this keyword does not function in the most intuitive way i.e. it doesn’t work in a traditionally object oriented way. The this keyword tends to refers to how a function was called depending on the enclosing object.

function foo() {
  return this
}

foo() // => 'this' refers to the window (or other top level object) becuase it is called at the top level

obj = { bar: foo } // assign foo to the bar property of this object
obj.bar() // => 'this' refers to obj

new foo() // => 'this' refers to the objec that inherits from the foo prototype

As a side note this does not exist for prototype objects. It seems that this only comes into being once an object that inherits from the prototype has been instantiated. So using this inside a prototype object WILL refer to that object instance.

function MyClass() { } 

MyClass.prototype.this // undefined

MyClass.prototype.foo = function() {
  this // => refers to an instance of MyClass
}

Bind

One of the more “interesting” things about Javascript is that when you extract a function from an object that uses the this keyword into a variable. The thing that this points to will change to reflect the scope in which it was extracted into. As a rule a function’s this refers to the place in which the function is being called not where it is defined.

One way to think of this is that when you assign a method (i.e. a function that belongs to an object) to a variable outside of that object, it is no longer a method but becomes a function and therefore the use of this to refer to an internal instance variable no longer makes sense. In the example below when the function associated with dog.talk is assigned in the talkFunction variable it loses its connection to the dog object.

let dog = {
  sound: 'woof',
  talk: function() {
    return this.sound
  }
}

dog.talk() // => 'woof'
let talkFunction = dog.talk
talkFunction() // => undefined

A good way to understand this loss of connection is to think about what the assignment actually does. It just adds the function definition directly to the variable in question. Therefore, its clear that a this defined outside of an object will be undefined as the talk variable on dog just points to a function definition.

let talkFunction = function() {
  return this.sound
}

Variables in the scope into which functions are extracted that have the same namespace as those defined in the context of the extracted function will overwrite those defined within the function’s context. In the example below, because sound is defined in the scope that talkFunction is extracted to, this.sound now points to 'meow' as defined by the scope in which the function is running.

let sound = 'meow'
let talkFunction = dog.talk
talkFunction() // => 'meow'

You can bind a function to the specific object context by using the bind keyword and submitting as an argument the object context that you want to bind to.

let talkFunction = dog.talk
talkFunction.bind(dog)
talkFunction() // => 'woof'

This with Callbacks and Objects

The problems with this means that callback or object functions placed into another function or object that have a reference to this will appear as undefined.

function MyClass() {
  this.foo = 'bar'
}

MyClass.prototype.caller = function(callback) {
  console.log(this.foo)
  callback()
}

myClass = new MyClass()
myClass.caller(function() {
  console.log(this.foo)
})
// => 'bar' because first 'this' was called inside the prototype caller object and refers to the object instnace
// => 'undefined' because 'this' in the callback refers to the top level object still because the function is just placed outside

This becomes more confusing when callbacks are placed inside prototypes.

function MyClass() {
  this.foo = 'bar'
}

function outerCaller(callback) {
  callback()
}

MyClass.prototype.caller = function() {
  console.log(this.foo)
  outerCaller(function() {
    console.log(this.foo)
  })
}

myClass = new MyClass()
myClass.caller()
// => 'bar' because first 'this' was called inside the prototype caller object and refers to the object instnace
// => 'undefined' because 'this' in the callback refers to the top level object becuase this function COULD BE defined outside of the prototype object entirely and then passed in

You can use bind inside callback arguments to access the this context that the callback is called in or the object that this refers to. This requires appending bind to the { } inside the argument. In the example below the callback is bound to the myClass instance object so that this refers to MyClass.

function MyClass() {
  this.foo = 'bar'
}

MyClass.prototype.caller = function(callback) {
  console.log(this.foo)
  callback()
}

myClass = new MyClass()
myClass.caller(function() {
  console.log(this.foo)
}.bind(myClass))
// => Bar

You can also use the enclosing context of a porotype with this to refer to a specific variable defined on an object. In the example below bind(this) is appended to the call back argument and because it is within a prototype definition the this will refer whatever prototype instance inherits from it.

function MyClass() {
  this.foo = 'bar'
}

function outerCaller(callback) {
  callback()
}

MyClass.prototype.caller = function() {
  console.log(this.foo)
  outerCaller(function() {
    console.log(this.foo)
  }.bind(this))
}

myClass = new MyClass()
myClass.caller()
// => Bar
// => Bar

Another way to solve the issue of this with callbacks and other scopes, is to use a self variable that is assigned as the this context which you want in your callback or object and then referencing that in the callback. In the example below self is defined inside the MyClass.prototype.caller function as the this context of that prototype and then used in the callback function instead of this.

function  MyClass() {
  this.foo = 'bar'
}

function  outerCaller(callback) {
  callback()
}

MyClass.prototype.caller = function() {
  console.log(this.foo)
  var  self = this
  outerCaller(function() {
    console.log(self.foo)
  })
}
myClass = new  MyClass()
myClass.caller()
// => Bar
// => Bar

Another possibility for solving this type of issue is to use an arrow function which means that the functions scope is looked as if were used like a variable, this means the scope that the function is used in inherits from that this.

function  MyClass() {
  this.foo = 'bar'
}

function  outerCaller(callback) {
  callback()
}

MyClass.prototype.caller = function() {
  console.log(this.foo)
  outerCaller(() => {
    console.log(this.foo)
  })
}
myClass = new  MyClass()
myClass.caller()
// => Bar
// => Bar

Privacy

Console

You can print to the std_out using the log function on the console object.

console.log('message to the std_out');
// => 'message to the std_out'

You can submit multiple arguments to be printed to the log function.

var first = 'hello';
var second = 'there';
console.log(first, second);
// => 'hello there'

Strict Mode

'strict mode' allows you to write safer Javascript by removing some of the more idiosyncratic tendencies of the language. You can use strict mode:

To ** use strict mode globally** place it at the beginning of your script at the top level before any other code.

'strict mode';
// other code

To use strict mode with a function place at the start of the function before any other code.

function strict() {
  'use strict';
  // function code
}

strict mode stops variables that have not been explicitly defined from being used. In regular Javascript mistyping a variable name with assignment results in the creation of a new global variable.

'use strict';
x = 3.141 // => ReferenceError

You cannot delete a function or variable in strict mode.

let spam = 'spam';

function ham(eggs) {
};

delete spam; // => SyntaxError
delete ham; // => SyntaxError

You cannot duplicate a parameter name in strict mode.

function spam(ham, ham) {
};
// => SyntaxError

Modules

Modules allow you to store interpolated Javascript code into a single file. These files can be named using the .mjs file extension, however, this only HAS to be the case when you use node if you want to use module specific features like the export and import keyword. When using a module on a webpage you must use type="module" inside the <script> tags to mark your .js files as modules to be loaded, again, if you don’t in some way indicate that the file is a module then you will not be able to use some of the ES6 module features.

<script type="module" src="./myModule.js"></script>

Asynchronous Javascript

Promises

The Promise class allows you to handle the results of asynchronous functions by wrapping them in a Promise object that accepts functions that will run depending on the results of that asynchronous function. In the function below timeOutPromise is defined with a single possible branch called resolve. The number of arguments passed into the Promise constructor is the number of branches that a promise can resolve to. This resolve function is called when the setTimeOut function completes after 1000ms. After this definition the promise is called with each then clause (in this case only one) matching the different branches defined in the Promise constructor. Whatever value is passed into the matching promise resolution branch will be retrievable here.

let timeOutPromise = new Promise(function(resolve) {
  setTimeOut(function() {
    resolve('done')
  }, 1000)
})

timeOutPromise.then(function(done) {
  console.log(done)
}) // => 'done'

You can also get the value out of a promise by calling Promise.resolve.

Async and Await

The async and await keywords allow you to define functions that use the resolve values of promise based asynchronous requests. Using the async keyword allows you to mark a part of your code as asynchronous and then use the await keyword to resolve a promise. In the example below, whatever is returned from the resolve of the timeOutFunction promise will be returned into the result variable. The body of this function will wait until this value has been returned before it continue executing. This is the only time you will get a direct value from a promise function, but its worth noting that this value is only available for the duration of the function.

function timeOutFunction() {
  let timeOutPromise = new Promise(function(resolve) {
  setTimeOut(function() {
    resolve('done')
  }, 1000)
  })
  return timeOutPromise
}

async function myFunction() {
  let result = await timeOutFunction()
  console.log(result) // => 'done'
  return result
}

It’s important to note that even though myFunction returns result, the result will not be available to synchronous code outside of myFunction that tries to use the result. In the example below calling console.log on myFunction will return a pending promise (because async functions returns promises, see below) that has not yet been resolved when the log function is executed thus it simply returns a pending promise. After this the await resolves timeOutFunction and the log within myFunction executes and prints the value directly. Importantly, to the outer scope of an asyn function the value of await is never directly exposed and is instead passed out as a value wrapped in a promise.

console.log(myFunction())
// => promise { pending }
// => 'done'

If you wanted to resolve the result of myFunction in the outer scope you would have to use a standard then clause.

myFunction().then(function(result) { console.log(result) })

Defining a function with the async keywords makes it return a promise automatically.

async function myFunction() {
  return 'hello'
}
myFunction() // => Promise

You can resolve this async returned promise by placing a function into the then of the promise. This executes with whatever the resulting return of the originally defined async function was.

async function myFunction() {
  return 'hello'
}

myFunction().then(function(resolve) {
  console.log(resolve)
}) // => 'hello'

Async Loops

At times you made to loop through a set of data and make an async request for each piece of data and THEN execute some other code. Much of the information on this is drawn from this article about looping with async. For example, imagine you have a page that makes a server API request for some corresponding information about a list of users, on the server side you need to loop through the information of each user and fire off an asynchronous database request to gather information on each user and the once ALL those requests are finished finally send data back to the client, or execute some other procedure. In the examples below the server request is mocked by the asynchronous userInformationServerRequest function that uses setTimeout to return information about the user after 1000 milliseconds.

A forEach based async loop DOES NOT WORK with async, it can never support async behaviour and does not recognise it . Looking at the code below you would expect the output to be start then looping with an await for each server request mocked by the setTimeout function that prints the transformed user information followed by end. However, in practice start and then end are printed followed by the information.

// forEach async example --> DOES NOT WORK
var users = [{name:  'dec'}, {name:  'marc'}, {name:  'phil'}];

var userInfo = {
dec:  10,
marc:  1,
phil:  23
}

async  function  updateUserInformation(usersArray) {
  console.log('Start');
  usersArray.forEach(async  function(user) {
    await  userInformationServerRequest(user);
  });
  console.log('end');
};

function  userInformationServerRequest(user) {
  return  new  Promise(function(resolve) {
    setTimeout(function() {
      user.age  = userInfo[user.name];
      console.log(user);
      resolve(user);
    }, 1000);
  });
}

updateUserInformation(users);
// => Start
// => End
// { name: 'dec', age: 10 }
// { name: 'marc', age: 1 }
// { name: 'phil', age: 23 }

You can use the .map method correctly process an array each element of which triggers an asynchronous request by mapping the array to an array of promises that is then resolved with the Promise.all function. In the updateUserInformation information below we use map to map each user in the array to a new Promise that makes a mock server request and resolves with the updated user information. Then the asynchronous Promise.all function is used with await to resolve all the promises we returned from map before logging them. Structuring async in this manner produces the behaviour in the correct order.

// async map example
// ... variable declarations removed for brevity
// ... check example above for var declarations

async  function  updateUserInformation(usersArray) {
  console.log('start');
  var userInformationPromises = usersArray.map(function(user) {
    return  userInformationServerRequest(user);
  });
  var updatedUserInformation =  await  Promise.all(userInformationPromises);
  console.log(updatedUserInformation);
  console.log('end');
}

function  userInformationServerRequest(user) {
  return  new  Promise(function(resolve) {
    setTimeout(function() {
      user.age  = userInfo[user.name];
      resolve(user);
    }, 1000);
  });
}

updateUserInformation(users);
// => Start
// { name: 'dec', age: 10 }
// { name: 'marc', age: 1 }
// { name: 'phil', age: 23 }
// => End

You can also use recursive async statements to model a loop WITHOUT relying on a traditional looping method by passing down information through an async that calls itself. In the example below the userInformationServerRequest calls itself for each successive request mutating the input array on each execution before returning the mutated array through the resolve callback function when it reaches the end of the list.

async  function  updateUserInformation(usersArray) {
  console.log('start');
  var startIndex =  0;
  var outputArray =  await  userInformationServerRequest(usersArray, startIndex);
  console.log(outputArray);
  console.log('end');
}

async  function  userInformationServerRequest(usersArray, index) {
  return  new  Promise(function(resolve) {
    setTimeout(async  function() {
      if(index === usersArray.length) {
        resolve(usersArray);
      } else {
        usersArray[index].age  = userInfo[usersArray[index].name]; //mutate array
        index++;
        var outputArray =  await  userInformationServerRequest(usersArray, index);
        resolve(outputArray);
      }
    }, 1000);
  });
}

updateUserInformation(users);
// => Start
// { name: 'dec', age: 10 }
// { name: 'marc', age: 1 }
// { name: 'phil', age: 23 }
// => End

Export and Import

To use ES6 classes in node you must either name your files with the .mjs extension to convert them to modules, or switch your entire project over to a module based project by adding a "type": "module" key-value pair to the package.json file.

ES6 Import

If you want to import an entire object and its associated methods from a file use the import command with the name of the object you want to import and a path to the file.

import Foo from './modules/foo.js'

You can import multiple objects by using standard de-structuring syntax.

import { Foo, Bar } from './modules/foo'

ES6 Export

You can export multiple functions directly by omitting the default keyword and containing the functions to be exported in {} curly braces.

const Foo = () => {}
const Bar = () => {}
const Baz = () => {}

export { Foo, Bar, Baz }