JavaScript is made up of essentially two categories of data types with differing characteristics.

Type 1: Primitive Data

The primitive data types are:

  1. Strings
  2. Numbers
  3. Booleans

Primitive data types all share the characteristic of immutability, or the inability to be changed. All operations on primitive data types will not change the original data by rather will copy the old data and create something new.

// let's start by creating a variable with a number
var myNum = 10;
// now let's attempt to increment the number by 1 
myNum + 1; // returns 11 
// now let's log myNum to check it's value 
console.log(myNum) // 10
// the original value has not changed
// there are several ways we can increment and store this value. 
// First, we can increment the value and store it in a new variable 
var newNum = myNum + 1
// We can also reassign it using a variety of 
myNum = myNum + 5
myNum = myNum * 3

// or we can use several syntactic shortcuts
myNum += 5
myNum *= 3

// if we're just going to increment or decrement by a one we can use:
myNum++
console.log(myNum)  // 11

### Type 2: Reference types The reference types are:
  1. Objects
  2. Arrays

Reference types are 'collections' of data. An array is a list of data that can accessed by an index while an object is a collection of data put in key-value pairs.

These data types are also mutable rather than immutable like primitive types. This means that they can be changed in place.

// let's start with an array
var myNums = [1, 2, 3, 4];

// We'll do a simple mutation by pushing a number to end of the array and log the results
myNums.push(5)
console.log(myNums)  // [1, 2, 3, 4, 5]
// It is important to understand that this operation _does not_ produce a new list
var new = myNums.push(5)
console.log(new)  // 5

### Passing Primitive and Reference Types into Functions

When passed as arguments to functions, the two types behave differently.

When we pass in a primitive type it makes a copy of the original value to use inside the function. Any changes that happens to a primitive data type inside the function does not happen to the original value.

Example:

var myNum = 5;

function addFive(num) {
    num += 5;
    return num
}

var fiveAdded =  addFive(myNum)
console.log(fiveAdded) // 10
console.log(myNum) // 5

However, when we pass in reference types into functions it does not copy, but rather passes as reference or pointer to the original value. Because of this any mutation that happens to reference types inside a function happens to the original value.

var myNums = [1, 2, 3];

function doubleEach (numList) {
    for (var i = 0; i < numList.length; i++) {
        numList[i] = numList[i] * 2
    }
    return numList
}

var newNums = doubleEach(myNums)
console.log(newNums)  // [2, 4, 6]
console.log(myNums)  // [2, 4, 6]

With reference types, although we can mutate them we don't necessarily have to.

// Array.prototype.concat does not mutate arrays
var num1 = [1, 2, 3];
var num2 = [4, 5, 6];
var num3 = num1.concat(num2)
console.log(num1) // [1, 2, 3]
console.log(num2)//[4, 5, 6]
console.log(num3)// [1, 2, 3, 4, 5, 6]

.map(), .reduce(), and .filter() are also good examples of built-in functions that do not mutate the original reference type.