Introduction

Add a semi-colon after every statement, to allow the compiler to differentiate statements (unlike the IDE).

Comparators and Expressions

Common number comparators are used: <, >, <=, >=, ==, !=, === (incl. type comparison), !== (incl. type comparison).

An expression is any valid unit of code that resolves to a value.

Conceptually, there are two types of expressions: those that assign a value to a variable and those that simply have a value.

The expression x = 7 is an example of the first type. This expression uses the = operator to assign the value seven to the variable x. The expression itself evaluates to seven.

The code 3 + 4 is an example of the second expression type. This expression uses the + operator to add three and four together without assigning the result, seven, to a variable.

Built-ins

Built-in functions can be used to get and send information to the user of the website

alert() // sends a message to the user in a small popup window
confirm() // asks a user for consent to move forward with action (OK = true boolean, Cancel = false)
prompt() // sends a message and retrieves an entry from the user
var userName = prompt("What’s your username”); // The answer of prompt can be stored in variable

typeof

typeof operator returns a string indicating the type of the unevaluated operand.
typeof operand // operand is an expression representing the object or primitive whose type is returned
typeof 37; // returns ‘number’
typeof true; // returns 'boolean'

null

null is a generic JS object.

console.log()

console.log() method prints from the file to the console.
- place expressions inside the enclosing parentheses of the console.log() method
- any expression can be placed in console.log()

Variables

JavaScript uses variables to store and manage data.

var example; // this is a declared variable
var example = ‘some string’; // this is a defined variable

Naming variables:
- no spaces in variables name
- no digits at the front
- camel case - camelCase

variable++ // incremental increase by 1
variable-- // incremental decrease by 1

Strings

A string is any value surrounded by quotes (single or double).
"this is a string"
'this is a string'

\t = adds tab stop
\n = adds new line
\\\ = \ in the string itself

Strings are case sensitive.

A \ prior to "quotation" will prevent string closing.

string.length // returns number value, including spaces and punctuation 
array.length // returns number value
string.charAt(10) // returns character at that index of string
== // compare exact contents of string, and return true or false

string.replace() method

Replace method will replace the contents of a string.
example = example.replace(‘part of string’, ‘replacement’);

Numbers

Numbers can be integers (2, 14, 4354) or they can be decimals, aka floats (3.14, 1.5 etc).

We can do basic math with familiar operators like +, -, *, /, %.

Math.round() method will round a number up
Number.toString() method will turn a number into a string

Order of Operations (PEMDAS)

- parentheses
- exponents
- multiplications
- division
- addition
- subtraction

Modulus or modulo operator

Modulus returns the remainder after division.
43 % 10 // returns 3

Loops

For-loop

For loops look like this:

for (var i=0; i<=10; i++) {  
  // log the numbers 0 through 10  
  console.log(i)  
}

The variable i is used to track how many times the loop has run.

The statement i<=10; indicates the limit of the loop. It will continue to loop if i is less than or equal to 10. The statement i++ increases the variable i by 1 each loop.

While-loop

While-loop runs its code as long as its boolean expression is true.
- continues to loop until condition inside parenthesis is false

while(*some expression is true*){
  *do this code!*
} 

Conditionals

if else

If Else allows us to execute certain code based on specific conditions.

if ( *some condition is true* ){
  *do this code*
} else {
  * otherwise do this code instead! *
}
var num = 10;
while(num>0){
  if (num % 2 == 0){
    console.log(num);
  }
  num--;
}

else-if syntax, if two conditions not enough

if ( *some condition is true* ){
  *do this code*
} else if ( *some OTHER condition is true* ){
  *do something for this condition * 
} else {
  * in all other cases, do this code instead! *
}

Nested conditional

- splitting results for a single condition
- inner else only responds to inner if, and out else to original if

Complex conditionals

- && binary ‘And’ returns true if both values are true
- || binary ‘Or’ returns if either value is true

Arrays

An array is an ordered collection of values.  Each value is an element, and each element has a numeric position in the array, known as its index.  Array elements may be objects or other arrays.  Arrays are a specialised form of JS object, and array indexes are really little more than property names that happen to be integers.

An array is a data structure with automatically indexed positions:
var arrayName = [‘passenger1', ‘passenger2']; // square brackets tell compiler to make an array and fill it with CSVs between the brackets

Array.filter() method

One common task is filtering arrays to only contain certain values.  We use the .filter() method for this.

var pets = ['cat', 'dog', 'elephant'];  
var filtered = pets.filter(function (pet) {  
  return (pet !== 'elephant');  
});  

Looping through Arrays

To access index’s value number (zero-based), we use:
arrayName[5]; // returns index 5
arrayName[5] = "New Item Value"; // adds string to array at index 5

Inside a for loop, we would use the i variable inside the square brackets instead of using an integer.

var pets = ['cat', 'dog', 'rat'];  
for (var i=0; i&lt;=pets.length; i++) {
  pets[i] = pets[i] + 's';
}
console.log(pets);

arrayName.pop(); // will pop off the last cell of the array and return its contents
arrayName.push("New cell contents"); // will push new cell contents
arrayName.shift(); // very first cell gets poped off array and returned
arrayName.length(); // will return the length of the array

Arrays can hold anything:
- strings, values, variables, other arrays or combinations of them all (sometimes called 2 dimensional arrays)

console.log( arrayOfArrays[0][1] ); // will return index cell 1 from 0 array
passengers[5] = undefined; // An undefined value creates "empty” cells in the array

Functions

Input > Function > Output

A function is a block of code that takes input, process that input, and then produces output.

A function "does something" step-by-step that we need to do repeatedly.  Wrapping code in a function allows us to reuse it. Return can go anywhere in function to instantly exit.

Functions are re-usable pieces of code.  Once created, functions can be stored in variable or object property, just like numbers and strings.

Declared Functions

Declared functions are loaded into memory immediately when the program loads, and held in memory until used (in contrast to function expressions).

Functions accept arguments, and arguments will be available for use be statements within the functions.

function titeOfFunction (argument1, argument2, argumentN) {
  * do some stuff *
  return * something or nothing from function process *
}
function sumOfCubes (a, b) {  
  var aCubed = a*a*a;
  var bCubed = b*b*b;
  return aCubed + bCubed;
}

sumOfCubes(4, 9);  // calls the function with the arguments 4 and 9  

Scope

Outside functions, the scope of the program is considered ‘global’ and variables declared there are accessible anywhere. Inside the function, the scope of the program is considered ‘local’ and variables declared there are only accessible inside the function.

Function expressions

Function expressions builds functions within code execution rather that at program load time.  Therefore, function expressions are only loaded when the line of code reached in the program.

Can build a function expression without a name, because being assigned to a variable that will hold the entire contents of that function.  A variable that holds a function can be passed into other functions.

Why?
- conserve program memory
- pass functions to other functions
- calls function immediately built

var diff = function (a, b) {  
  return a*a - b*b;
};
diff( 9, 5 ); // function expressions are called with the variable name, passing in the input arguments
console.log(diff) // returns the body of the function

Compared to declared functions (see above) which built in memory immediately the program loads:

function diffOfSquares (a, b) {
  return a*a - b*b;
};

Anonymous functions

An anonymous function is a function without a name:

function (noName) {
  return noName;
}

Stored functions

A variable that holds a function can be passed into other functions:

var greeting = function() {
  alert("Greetings");
}
closeTerminal( greeting ); // closeTerminal function called passing in greeting variable

function closeTerminal ( message ) {
  message(); // calls the passed in function.  In this case, greeting
};

Array.Map()

var numbers = [array of numbers];
var results = numbers.map(function (arrayCell) {
  return arrayCell * 2 ;
});

- map() method will always take in a function as a parameter, and return a new array with the results
- whatever the map function does, it will do to every individual cell of the array
- map works like a loop that applies a function to each array index.
- usually built in one line for clarity

Returning functions and immediate invocation

- functions can also return functions; since functions can be treated as expression, they can also be returned like values
- to call the function contained in the variable, need parenthesis and semicolon - function(); - so JS knows calling the function
- can immediately call the function returned by the function - returns the function that it builds
no var = necessary, remove var = and include (); on the end and variables stored in ‘closure’

Closures

- when return a function from a function and complete with variables that showed up in the external function, we have a closure (ie. variables returned within the returned function are defined outside the returned function)
- the entire contents of a returned function will be available outside the outer function when they are returned
- a closure wraps up an entire environment, binding all necessary variables that come from other scopes. Closures take variables from external scopes and bind them in local scopes of other functions
- a functions local variables aren’t available once the function’s scope is closed.

For example:

function testClosure () {
  var x = 4;
  return x;
}
testClosure(); // returns 4
x; // returns undefined

Compared to a closure:
Inner function can access outer function's scope / variables. X is not stored anywhere in closeX, not even as a parameter. closeX looks first inside closeX for x, if not there will look outside for x in testClosure.

function testClosure() {
  var x = 4;
  function closeX () {
    return x;
  }
  return closeX;
}
var checkLocalX = testClosure();
checkLocalX(); // returns 4

Even though testClosure has finished operating (its scope is closed), can still access the local variable that was declared in that function.  This is because x has been bound as a closure inside closeX.

function buildCoveTicketMaker( transport ) {
  return function ( name ) {
    alert("Here is the message about " + transport + " to " + name);
  }
}
var getSubmarineTicket = buildCoveTicketMaker('Submarine');
getSubmarineTicket; // would return function, however bound variables will not be evident inside a stored function

Modifying bound vales after closure

Closures can modify bound variables in the background.

function buildCoveTicketMaker( transport ) {
  var passengerCount = 0;
  return function ( name ) {
    passengerCount++;
    alert("Here is the message about " \+ transport + " to " \+ name\nYou are passenger number" \+ passengerCount);
  }
}
var getSubmarineTicket = buildCoveTicketMaker('Submarine');
getSubmarineTicket("Todd"); // passengerCount 1
getSubmarineTicket("Mario"); // passengerCount 2

Even though the returning function's scope disappears each time, it has retained the value of the incremented variable.

Common mistakes with closures

Closures bind at their very last opportunity.  Must pay attention to when return the function, because the final state of the variables when returned, is the state that is bound.

For example, in a loop.  If closure returns after the loop and var i bound, will return for the whole loop not the value at the if statement.

Hoisting (load order)

Ensuring every line of code can execute when its needed

Program compile order:
- First, memory is set aside for all necessary variables and declared functions
- variables initially undefined
- then executable code runs
- Function expressions are never hoisted, they are treated as assignments

Hoisting options:
1.
- variable declarations and assignments to the top
- conditional code to the bottom
2.
- don’t have function expressions, use declared functions instead, because the declared functions will be hoisted to the top above the conditional code.

Objects

JS is classless, its inheritance is done through prototypes.

In JS fundamental data type is the object.  An object is a composite value: it aggregates multiple values (primitive values or other objects) and allows you to store and retrieve values by name.

An object is an unordered collection of properties, each of which has a key and a value.  Property names are strings, so can say objects map strings to values.

- re object orientated programming languages
- objects are ‘containers’ of related information
- multiple pieces of data, called properties, are grouped within an Object
- typically objects created because want to refer to properties together
ie - OBJECT: property1, property2 etc
i.e - BOOK: title, author, publisher, numChapters, numPages, illustrator
- objects often called ‘composite value’ - because contains multiple pieces
- properties can refer to numbers, strings, arrays, functions, and even other Objects
- many different ways to build Objects

Object Literals

var myBox = { propertyName: 'propertyValue’ };
- curly brackets make new object in JS and set properties on it
- Object properties accept variables

Object Constructor

var kitchen = new Object(); // use the new keyword followed by call to constructor function

Object Properties

myObject.propertyName;  // accesses object property
myObject['propertyName'] // also access object property
console.log( myObject.innerObject.property ); // can access inner objects within objects
console.log( myObject[‘innerObject’]['property'] ); // can access inner objects within objects
myObject.newProperty = 24; // dot operator can be used to set new property after object constructed
myObject.arrayProperty.push("New array cell content"); // can use all the array methods with within objects
delete object.property; // will always return true, even if no property exists - is this property gone? true

Object functionality (aka methods)

The properties of objects can also be functions.  An object’s function properties are often called its ‘methods’. These functions (methods) belong to the object rather than exist outside the object for the entire program.

var object = {
  Prop1: { name: "me" },
  method: function ( name ) { ... }
};
object.method("you");

Within an objects methods can’t access other properties directly.  Instead, use keyword ‘this’, which is a reference to the object the method was called on. This always refers to the owner Object of the function in which 'this' is used.

Methods are only loosely tied to the objects they’re attached to.  Method objects have their call method that lets you specify any value you want for this.

Counting in Objects - enumeration with the for-in loop

- Objects don’t have a native length like arrays or strings, so can’t use length with Objects to loop through:
object.length; // returns undefined
- for-in loop allows us to access each enumerable property in turn

numType = 0;
for ( key in myObject ) {
  console.log(key) // each property name logged as string
  if (myObject[key].type == 'myType') {
    numType++;
  }
}

- key represents every single property present inside myObject
- in keyword looks in myObject, and finds each enumerable property in turn
- key could be any word (e.g. item, p, keyword etc)
- if looking for type, a method.type would return undefined
- if counting / enumerating as a method, use this keyword to refer to object itself

Prototypes

A prototype is an object on which other objects are based.
- inheritance (common object orientated idea) - passing down properties through inheritance
- Objects have a ‘parent’ object that gives them properties
- an Object’s parent is called its prototype, and all the properties belong to and come from the prototype
- a prototype is like a blueprint Object for the Object we are creating

When an object is created, that object's prototype will pass it many additional properties.  Passing down properties is called inheritance.  Inheritance helps avoid over-coding, building multiple properties or methods into similar objects. I.e. it avoids not having many storage locations for the same information.

All native JS data structures inherit all of their properties and methods from their very own prototypes:

Object Prototype - highest level in JS hierarchy. Its children (Array Prototype, String Prototype, Number Prototype, Function Prototype) inherit from Object Prototype.

Object Prototype includes properties such as:
- valueOf, constructor, toLocaleString, toString, isPrototypeOf, propertyIsEnumerable, hasOwnProperty

Array Prototype - next in hierarchy for arrays:
- length, pop, push, shift, reverse, sort, reduce, join, slice

String Prototype - next in hierarchy for strings:
- length, charAt, time, concat, indexOf, replace, toUpperCase, toLowerCase, substring

Number Prototype - next in hierarchy for numbers:
- toFixed, toExponential, toPrecision

Function Prototype - next in hierarchy for functions:
- name, bind, call, apply

These properties are passed down into any Array object, String object etc when created, so can call each method or properties on the created object.

Parent properties also available to children.  i.e. Array Prototype inherits the Object Prototype properties and methods.

Though the properties are inherited, they are still ‘owned’ by prototypes, not the inheriting child Object.  This means inherited properties are stored with the ancestors and stay there, which is effective from memory management.

An object will search up its prototype chain for properties or methods used.

For example:

var myString = "String";
myString.hasOwnProperty();

hasOwnProperty() will look to itself, then String Prototype, and finally Object Prototype. The prototype provides access to the hasOwnProperty method without it needing to be stored in myString.

Adding inheritable properties to prototypes

Can add base values or functionality to ALL objects of similar type.  Can add functionality to String Prototype for example, and then will be available to all strings via inheritance.

Since we are giving function to String Prototype, don't need to pass the function the string because the string the calling the function itself.

String.prototype.countAll = function ( letter ){
  // whatever function to add to the String Prototype
  var letterCount = 0;
  for (var i = 0; i<this.length; i++) {
    if (this.charAt(i).toUpperCase() === letter.toUpperCase() ) {
      letterCount++;
    }
  }
  return letterCount;
};

Can then call with any string:
myString.countAll("I"); // will return number of Is

Inheritance and Constructors

Using inheritance, we can create new Objects with our existing Objects as prototypes using object.create( prototypeObject ).

For example:

var shoe = { size: 6, gender: "woman" };
var magicShoe = Object.create( shoe );

- the first argument shoe of the object.create method will be used as the prototype of the newly created object
- magic will inherit all properties from variable shoe object if logged out

Can discover the prototype chain with isPrototypeOf. Will look up entire prototype chain:
Object.prototype.isPrototypeOf ( shoe ); // will return true if any specific Object is a prototype of another
shoe.isPrototypeOf( magicShoe ); // will return true
magicShoe.isPrototypeOf( shoe ); // returns false

Can build a prototype with empty properties (undefined), if want to flesh out different kinds of objects.
1. determine common properties of a shoe class
- a class is a set of objects that all share and inherit from the same basic prototype
- All Shoes (size, gender etc) & Some Shoes (laces, workboots etc)
2. build a constructor for the class
- a constructor allows us to set up inheritance while also assigning specific property values
- capitalising a functions name distinguishes it in JS as a constructor, or class of objects
- a constructor will construct a new instance of the "Class", and assign values to it.
- JS ‘new’ keyword produces a new Object of the class, or ‘instantiates’ the class

Constructor example
When a call to the function is preceded by the keyword new, the this variable gets set to a new object instance which will automatically be the functions return value.

function Shoe (shoeSize, shoeColour, forGender, constructStyle) {
  // this keyword will automatically refer to the new instance of the class being created
  this.size = shoeSize;
  this.colour = shoeColour;
  this.gender = forGender;
  this.construction = constructStyle;
  this.putOn = function () { alert("Shoe On!") };
  this.takeOff = function () { alert("Shoe Off!") };
}
var newShow = new Shoe(12, "green", "women", "slipper");

The returned object will also have reference to the constructor used to create it (Shoe.constructor).

Don’t want to call a constructor function without the new keyword, otherwise this set to global scope.

Can set the common elements on the prototype of the constructor.
1. Assign a prototype to a constructor
- by setting a constructor's prototype property, every new instance created will refer to common properties

Shoe.prototype = {
  putOn: function () { alert("Shoe On!") };
  takeOff: function () { alert("Shoe Off!") };
}

Prototypes can also refer back to the instance:

Shoe.prototype = {
  putOn: function () { alert("Shoe On!" \+ this.construction) };
  takeOff: function () { alert("Shoe Off!" \+ this.size) };
}

Overriding Prototypal Methods

valueOf(); // returns the value in the primitive type associated with the object

Important to consider inheritance when overriding: don't necessarily want to override method on the Object Prototype because would impact entire program.

May only wish to override on the prototype of the object.

Create a new property on the object:

Tornado.prototype.valueOf = function () {
     ... updated method...
}

In above instance, valueOf found in the Tornado prototype not the Object Prototype.  Tornado Prototype is earlier in the Prototype chain, so that new valueOf method is used instead of the Object Prototype valueOf.

Finding an Object's Constructor and Prototype

Some inherited properties provide way's to find an Object's nearest prototype ancestor.

myInstance.constructor; // returns entire constructor function
myInstance.constructor.prototype; // returns prototype object associated with that constructor
myInstance.__proto__; // same as above, can use to move up prototype chain

hasOwnProperty() helps identify location. Can use to search for location of properties:

Object.prototype.findOwnerProperty = function (propName) {
  var currentObject = this;
  while (currentObject !== null) {
    if (currentObject.hasOwnProperty(propName)) {
      return currentObject;
    } else {
      currentObject = currentObject.__proto__;
    }
  }
  return "No property found";  
}