JavaScript Fundamentals

Data Types

  1. undefined
  2. Boolean
  3. Number
  4. String
  5. Symbol
  6. null
  7. object

undefined and null in JavaScript

  • undefined mean a variable has been declared but not yet been assigned a value. The data type of undefined variable is also undefined. (undefined is a data type).
1
2
3
var x;
alert(x); // undefined
alert(typeof x); // undefined
  • null is an assignment value, it can be assigned to a variable as a representation of no value. The data type of null variable is an object.
1
2
3
var x = null;
alert(x); // null
alert(typeof x); // object
  • undefined and null are equal in value but different in type.
1
2
3
4
5
typeof undefined; // undefined
typeof null; // object

null === undefined; // false
null == undefined; // true

Declare variable

  • var: normal way to declare a variable.
  • let: the variable you declared will only be used within the scope of where you declare it.
  • const: the variable value will never change

Scope

  • Local scope
  • Global scope

JavaScript has function scope, each function creates a new scope. Scope determines the accessibility of these variables. Variables defined inside a function are not accessible from outside the function

Array

  • push: Add anitem to the end of the array
  • pop: Remove an item from the end of the array
  • shift: Remove an item from the beginning of an array
  • unshift: Add an item to the beginning of an array
  • indexOf: find the index of an item in the array
  • splice: Remove items from an index position.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let vegetables = ['Cabbage', 'Turnip', 'Radish', 'Carrot']
console.log(vegetables)
// ["Cabbage", "Turnip", "Radish", "Carrot"]

let pos = 1
let n = 2

let removedItems = vegetables.splice(pos, n)
// this is how to remove items, n defines the number of items to be removed,
// starting at the index position specified by pos and progressing toward the end of array.

console.log(vegetables)
// ["Cabbage", "Carrot"] (the original array is changed)

console.log(removedItems)
// ["Turnip", "Radish"]
  • slice: copy an array

Object.freeze

  • const: creates an immutable binding, you cannot re-assign a new value to the binding. But if you delcare a const array or object. You can set new value to the element in the array or object
  • object.freeze: makes an object immutable, so you cannot change its properties.

Object Dynamic Properties

The property ‘test’ is a dynamic property, it’s value will be evaluated during runtime. So obj will have a property name ‘test’ with value 52.

1
2
3
4
5
6
7
8
9
10
const test = 'answer';

const obj = {
p1:10,
p2:20,
[test]: 52
};

console.log(obj.test);
console.log(obj.answer);

Anonymous function

  • functions without name. You can also pass that function to a variable
1
2
3
var magic = function() {
return new Date();
}

Arrow function

  • You can convert anonymous function to arrow function
1
2
3
4
5
var magic = () => {
return new Date();
}

var magic = () => new Date();
  • Arrow function with parameters
1
var myConcat = (var1, var2) => arr1.concat(arr2);

Example: Filter the array with only positive numbers and return the square of all remain elements in a new array

  • Array.filter: The filter() method creates a new array with all elements that pass the test implemented by the provided function.
  • Array.map: The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const array = [1,2,-3,4,-5,6,7];

const squareList = arr => {
const squaredList = arr.filter(function callback(num) {
return Number.isInteger(num) && num > 0;
}).map(function square(num) {
return num * num;
});

return squaredList;
}

const squaredIntegers = squareList(array);

console.log(squaredIntegers);
  • Using Arrow functions
1
2
3
4
5
6
7
8
9
const array = [1,2,-3,4,-5,6,7];

const squareList = arr => {
const squaredList = arr.filter(num => Number.isInteger(num) && num > 0).map(num => num * num);
return squaredList;
}

const squaredIntegers = squareList(array);
console.log(squaredIntegers);

Example: Write a function that takes multiple parameters and add them up

1
2
3
4
5
6
function sum(x, y, z) {
args = [x, y, z];
return args.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
}

console.log(sum(1,2,3));
  • Regular functions give access to their calling environment while arrow functions give access to their defining environment

  • The value of the ‘this’ keyword inside a regular function depends on HOW the function was CALLED (the OBJECT that made the call)

  • In arrow functions, this keyword doesn’t mean the caller of the arrow function. The value of the ‘this’ keyword inside an arrow function depends on WHERE the function was DEFINED (the scope that defined the function). This makes it great for delayed execution cases like events and listeners.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const test = (function test () {
const testerObj = {
func1: function() {
console.log('func1', this);
},

func2: () => {
console.log('func2', this);
},
};

testerObj.func1();
testerObj.func2();
})()

Using Rest operator to represent multiple parameters

  • Rest Operator: The rest parameter syntax allows a function to accept an indefinite number of arguments as an array,

  • Reduce: The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in single output value.

  • The reducer function takes four arguments:

  1. Accumulator
  2. Current Value
  3. Current Index
  4. Source Array
  • Your reducer function’s returned value is assigned to the accumulator, whose value is remembered across each iteration throughout the array, and ultimately becomes the final, single resulting value.
1
2
3
4
5
function sum(...args) {
return args.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
}

console.log(sum(1,2,3,4));

Spread syntax

Spread syntax (…) allows an iterable such as an array expression or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected, or an object expression to be expanded in places where zero or more key-value pairs (for object literals) are expected.

1
2
3
4
5
6
7
8
9
10
11
12
const arr1 = ['JAN', 'FEB', 'MAR', 'APR', 'MAY'];

let arr2;

(function () {
// spread arr1 into individual elements and create a new array by surrond it with []
arr2 = [...arr1];
arr1[0] = 'potato';
})();

// arr2[0] will still be 'JAN'
console.log(arr2);

Destructuring assignment

The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.

1
2
3
4
5
var obj = {x:3.6, y:7.4, z:6.5};

const {x : a, y: b, z: c} = obj;

console.log(`${a} ${b} ${c}`);
  • Destructuring Assignment: Nested Objects
1
2
3
4
5
6
7
8
9
10
11
12
const LOCAL_FORECAST = {
today: {min : 72, max: 83},
tomorrow : {min : 73.3, max: 84.6}
};

function getMaxOfTmw(forecast) {
const {tomorrow : {max : maxOfTomorrow }} = forecast;

return maxOfTomorrow;
}

console.log(getMaxOfTmw(LOCAL_FORECAST));
  • Destructuring Assignment: Arrays
1
2
const[x, y, , z] = [1,2,3,4,5,6];
console.log(x, y, z);
  • Destructuring Assignment: Pass an object
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const stats= {
max: 56.7,
standard_deviation: 4.34,
median: 34.54,
mode: 23.5,
min: -0.4,
average: 45.6
}

function half({max, min}) {
return (max + min) / 2.0;
}

console.log(half(stats));

Object Literal Declarations Using Simple Fields

1
2
3
const createPerson = (name, age, gender) => ( {name, age, gender} )

console.log(createPerson('Yuan Cheng', 27, 'male'));

Functions in Objects

1
2
3
4
5
6
7
8
9
const bicycle = {
gear : 2,
setGear: function(newGear) {
this.gear = newGear;
}
};

bicycle.setGear(3);
console.log(bicycle.gear);
  • we could remove the ‘function’ keyword
1
2
3
4
5
6
7
8
9
const bicycle = {
gear : 2,
setGear(newGear) {
this.gear = newGear;
}
};

bicycle.setGear(3);
console.log(bicycle.gear);

class syntax

1
2
3
4
5
6
var SpaceShuttle = function(targetPlanet) {
this.targetPlanet = targetPlanet;
}

var zeus = new SpaceShuttle('Jupiter');
console.log(zeus.targetPlanet);
  • Using Class and Constructor
1
2
3
4
5
6
7
8
class SpaceShuttle {
constructor(targetPlanet) {
this.targetPlanet = targetPlanet;
}
}

var zeus = new SpaceShuttle('Jupiter');
console.log(zeus.targetPlanet);

getters and setters

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Book {
constructor(author) {
this._author = author;
}

// getter
get writer() {
return this._author;
}

// setter
set writer(updatedAuthor) {
this._author = updatedAuthor;
}
}

import vs require

import functions from other js files

1
import {capitalzeString} from "string_function"

export

The export statement is used when creating JavaScript modules to export live bindings to functions, objects, or primitive values from the module so they can be used by other programs with the import statement. Bindings that are exported can still be modified locally; when imported, although they can only be read by the importing module the value updates whenever it is updated by the exporting module.

  • below code is saved in a js file: string_function
1
export const capitalizeString = str => str.toUpperCase();

* to import

import * will import every functions you export in the other file to a object

1
import * as capitalizeStrings from "capitalize_strings";

Named export vs export default

Named export: With named exports, one can have multiple named exports per file. Then import the specific exports they want surrounded in braces. The name of imported module has to be the same as the name of the exported module.

Export default: One can have only one default export per file.
The naming of import is completely independent in default export and we can use any name we like. No curly braces needed when import

Promises

A promise is an object that might deliver data at a later point in the program.

Fetch API will return a promise, to consume that promise, we do a .then call on the result of fetch and supply a callback function. The Fetch API will have a raw response ‘resp’, you need to call the .json method on that response object. The json method is also a asynchronous function. It also returns a promise. So we do another .then call on the result of the json function

1
2
3
4
5
6
7
8
9
const fetchData = () => {
fetch('https://api.github.com').then(resp => {
resp.json().then(data => {
console.log(data);
});
});
};

fetchData();

The above code works, but it is difficult to read. We could use async/await.

1
2
3
4
5
6
7
8
9
const fetchData = async () => {
const resp = await fetch('https://api.github.com');

const data = await resp.json();

console.log(data);
};

fetchData();

the async function is another way for us to consume promises without having us to use .then calls