JavaScript Fundamentals

Peter Reznick
Jun 12, 2017 · 14 min read

This is the first post in a series on JavaScript, and is based on notes I created for myself in preparation for Launch School’s first JavaScript assessment. I based these notes off of Launch School’s course materials and MDN’s JavaScript documentation.

The series will move through different areas of JavaScript in the abstract, with a narrowing focus, and then address specific problems I’ve encountered when using JavaScript in a web development context. The post was originally published here.

Primitive Values

In JavaScript, there are six primitive data types:

  • boolean
  • string
  • number
  • null
  • undefined
  • symbol (New in ECMAScript 6)

and one compound type:

  • object

The most important practical distinction between primitives and non-primitives is mutability. Primitives are immutable, which means that they cannot be altered, while objects are mutable; they can be changed and retain their identity. Primitives are also defined by the fact that they are not objects and have no methods.

Data type can be determined using the typeof operator.

When methods are called on primtive data types, they make use of the Object.prototype construction, which briefly transforms the primitive into its compound counterpart, executes the method, and then converts back into the primitive. The primitives boolean, string, number and symbol all have object counterparts, which can be created explicitly using the following syntax, with the literal as argument:

var myStr = new String('Hello, world!');

If we desire to change a primitive value, we must use reassignment.


JS is a dynamically-typed language; this means that a variable can hold a reference to any data type and be reassigned to any other data type over the course of the program. This happens because JS performs checking at run time rather than compile time.

Changing a primitive of one type into another type in JS requires a conversion (or coercion) operation. Since primitives are immutable, this means performing a method call on a primitive and returning a different-type primitive.

String to number coercions can be performed with the following methods:

Number('5'); // 5

parseInt('5.5', 10); // 5
parseFloat('5.5', 10); // 5.5

parseInt always returns whole numbers, while parseFloat returns floating point numbers. The second argument is the radix, which determines the base for the return value.

String(123); // '123'
String(123.5); // '123.5'
String(true); // 'true'
Boolean(0); // false
Boolean('hi there'); // true

!!(0); // false
!!('hi there'); // true

NB: The following five values are ‘falsy’:

  • 0
  • ‘’
  • undefined
  • null
  • NaN

This means that they will resolve to false when evaluated in the conditional portion of a control statement.

The unary + operator attempts to convert values into numbers, while the binary operator performs String concatenation or arithmetical addition.

  • If either operand is a String, the other operand will be converted into a string
  • If either operand is a number, and the other is not a string, then the non-number operand will be converted to a number.

While the non-strict equality operator attempts coercions, the strict (===) equals operator does not.


In JS, strings have no size limit and can be defined with either single or double quotation marks, with no functional difference between the two. They can hold any character in the UTF-16 charset, and use an escape sequence \ + $formattingChar to handle formatting characters as well as quotation marks.

Characters can be accessed in strings using the String.prototype.charAt() method. Square brackets perform the same operation:

var str = 'hello';
str.charAt(1) === str[1]; // true

A string’s length can be returned using the .length property.

String.prototype.indexOf(string) returns a number corresponding to the first occurance of the character or substring argument in the receiver. Returns -1 if no match.

String.prototype.lastIndexOf(string) returns a number corresponding to the last occurance of the character or substring argument in the receiver. Returns -1 if no match.

String.prototype.replace(string/pattern, replacement) performs a subsitution operation, replacing by default the first occurance of a match with the replacement string.

The match can be made global by supplying a pattern with the g flag, while the replacement can be a functional expression. In this case, every code match will be passed to the function and replaced by the corresponding return value:

'hey this is peter'.replace(/\s[a-z]/g, function(char) {
return char.toUpperCase();
// 'Hey This Is Peter'

String.prototype.split(substring/pattern) returns an array of substrings separated by the substring or pattern supplied to the method.

NB: The argument itself will be excluded from the returned array.

String.prototype.substr(start[, width]) returns a substring starting at start and, by default, extending to the end of the string. If an optional width value is provided, then the method returns a substring starting at start and extending to start + width, non-inclusive, or the end of the string, if less than start + width.

String.prototype.substring(start[, end]) returns a substring starting at index start and ending at index end or the end of the string, if end isn't provided. If start is less than end, substring will swap the values.

NB: substring treats negative or NaN arguments as 0.

String.prototype.slice(start[, end]) functions like substring, except:

  • it does not switch values is start is less than end (returning an empty string instead)
  • it can handle negative arguments.

String.prototype.toUpperCase() and String.prototype.toLowerCase() return a copy of the receiver string with all letter chars converted to upper or lower case, respectively. Other chars (digits, whitespace, non-alphanumerics) are unchanged.

Flow Control

if statements in JS have three parts: an expression that evaluates to a boolean value, a conditional statement that incorporates the expression, and a code block that executes if the boolean expression evaluates to true:

if (score > 70) {
console.log('Congratulations, you passed!');

in this case:

  • expression: score > 70
  • statement: if (score > 70)
  • code block: { console.log('Congratulations, you passed!')

an if statement can be followed by an optional else statement, which results in the execution of an additional code block in the event that the first boolean expression evaluates to false:

if (score > 70) {
console.log('Congratulations, you passed!');
} else {
console.log('Study more!');

an if can be appended to an else clause, rendering the else clause's execution contional to an expression:

if (score > 70) {
console.log('Congratulations, you passed!');
} else if (score > 90) {
} else {
console.log('Study more!');

A switch statement compares an expression to a set of cases, executing the code associated with the matching case:

var opt = 1;

switch(opt) {
case 1:
// code
case 2:
// code
case 3:
// code

In the example above, only the code under case 1 will execute.

NB: without break at the end of the case, each subsequent case and default will execute.

The for loop combines the three elements of any loop in a single statement: initial expression, condition, increment expression. Standard form is as follows:

for (var i = 0; i < 10; i += 1) {

The while loop first evaluates the condition incorporated into the while statement, and executes the code block if it is true. It repeats this process until the expression evaluates to false:

var i = 0;

while (i < 100) {
i += 1;

Similar to a while loop, do...while evaluates the expression after the block of code has executed, meaning that every do...while loop will be executed at least once:

var counter = 0;
var limit = 0;

do {
counter += 1;
} while (counter < limit);

Variable Scope and Hoisting

A variable’s scope is that portion of the program that can reference the variable by name, the part of the program where the variable is ‘visible’.

In JavaScript, global scope is the highest level of visibility. Global-scoped variables are accessible throughout the program. Function scope, is local scope, and is defined by the function definition. Function-scoped variables are only visible inside of the function and in nested scopes.

Global-scoped variables can be created by omitting the keyword var during variable declaration, or by declaring the variable in lexically global space in the program.

NB: Lexical scoping refers to a system in which a variable’s scope is determined by its location in the source code.

Function-scoped variables can be created by declaring the variable with the keyword var inside of a function, or by means of function parameters. Even if an argument isn't passed to the function, the parameter is still effectively declared.

JS scans for variable declarations in a given scope before executing the code. For this reason, a variable declared anywhere in scope is equivalent to a variable declared at the top of the scope, behavior that is called hoisting. Variable assignments are not hosted however. Thus, the code below outputs undefined, rather than Hello, world!, because the declaration of a is hoisted above the logging operation, but not the assignment.


var a = 'Hello, world!';

Hoisting also applies to function declarations and statements. Note, however, that function declarations are hoisted above variable declarations.

Thus, the code below outputs Goodbye, world!, because the function declaration, though located below the variable declaration in the source code, is hoisted it above it, meaning that the value assigned to the variable a is what is output by the logging operation.

var a = 'Goodbye, world!';

function a() {
console.log('Hello, world!');

console.log(a); // Goodbye, world!

Function Declarations, Expressions and Scope

A function in JS is a piece of code that is stored in one place and accessible from elsewhere in the program. Like variables, functions must be declared before they can be used. Such declarations must include:

  • the function keyword
  • the name of the function
  • an optional list of comma-separated parameters
  • a block of statements (the function body)
function myFunction(par1, par2) {
// function body

NB: unless the function includes a return statement, it will return undefined.

  • parameter: the variables supplied to a function, defined in the function definition
  • argument: the values passed into the function at call time

In JS, every function creates a new scope. Function scope is the part of the program that is contained within a function definition. Function-scoped variables are accessible within the function and in all lower scopes, but not in higher scopes.

In JS, “A closure is the combination of a function and the lexical environment (or simply “environment”) within which that function was declared.” Environment here means any local variables that were in scope when the closure was created.

In practice, closures allow functions to reference outer-scope local variables even when called from a different scope, as in the example below:

function outer() {
var name = 'Peter';

function callName() {

return callName;

var fun = outer();
fun(); // outputs: Peter
console.log(name); // throws reference error

Even though callName() is referenced (via the variable fun) from a scope in which name is not declared (as demonstrated by the logging operation on the last line), it still outputs Peter because its closure retains the reference to all local variables in scope at the time of its creation.

A function declaration defines a variable whose type is function (variable declaration and assignment are combined) without explicit variable assignment, while a function expression defines a function as part of a larger syntax, typically that of variable assignment.

// function declaration:
function foo() {
// function body

//function expression
var bar = function() {
// function body

Object Properties and Mutation

JS uses objects to organize code and data. Objects can be created with the literal syntax:

var obj = {
prop1: 'hello',
prop2: 'world'

or with the new Object() or Object.create() constructors.

Objects contain data (state) and behavior, which are defined using properties and methods, respectively.

Property names can be any valid string, and a property value can be any valid expression including functions and objects.

Property values can be accessed using dot notation:


or bracket notation:


NB: when declaring a new property using bracket notation, string literal syntax must be used (if the argument is not a number). Otherwise, the argument will be interpreted as a variable name, leading to potentially undesirable outcomes.

In JS, primitives are immutable, while objects are mutable, that is, they can be altered without losing their identities. This is possible because objects contain inner data; this is what is altered.


Arrays are the basic collection type in JS, and can be created using either the array literal syntax or the constructor:

var arr = new Array(1, 2, 3)

// equivalent to

var arr2 = [1, 2, 3];

Bracket notation can be used to access and add values to an array based on index.

NB: Any unassigned index will return undefined.

The length property of an array is procedurally generated; it is equal to the highest integer index value + 1 and does not depend on the number of property values held by the array. It can also be set manually:

var arr = [];
arr.length; // 0
arr[5] = 0;
arr.length; // 6
arr.length = 100;
arr.length; // 100

Since arrays are objects, any data type can be used as a property. However, when retrieving property names that are not numbers (integer or fractional) it is necessary to use the string literal syntax; otherwise, the property name will be interpreted as a variable name, with unpredictable results.

In order to ascertain whether an object is an array use: Array.isArray(object) which returns a boolean value.

Array.prototype.pop() removes the last element from the array and returns that element, changing the length of the array.

var arr = [1, 2, 3];
arr.pop(); // 3

arr; // [1, 2]

Array.prototype.push() adds an element to the end of the array and returns the new length of the array.

var arr = [1, 2, 3];
arr.push(4); // 4

arr; // [1, 2, 3, 4]

Array.prototype.shift() removes the element at index 0 and shifts all subsequent elements down by one, returning the value of the removed element.

var arr = [1, 2, 3, 4];
arr.unshift(); // 1

arr; // [2, 3, 4]

Array.prototype.unshift() adds one element at index 0, and then unshifts the subsequent elements up by one, returning the length of the array.

var arr = [1, 2, 3];

Array.prototype.slice(start[, end]) returns a shallow copy of the array starting at start, inclusive, and continuing through the last index of the array. If optional end value is provided, the copy stops at index end, non-inclusive.

Array.prototype.splice(start[, deleteCount[, item1[, item2 etc...]]]) changes the content of the array by removing existing elements and possibly inserting new elements.

The function removes a deleteCount-width slice of the array, and inserts any new elements after start. If no deleteCount is provided, then all elements after start are removed.

The function returns an array containing the deleted elements.

Array.prototype.concat(arr) returns a new array consisting of the elements of the receiver array followed by the elements of the argument array. Neither array is altered.

Array.prototype.join([separator]) iterates over the receiver array, coercing each element to a string and then joining the strings with a default ',' or the optional separator argument.

Assignments and Comparison

The assignment operator = sets the left operand equal to the value of the right operand. Compound assignment operators (like +=) combine arithmetic operators with assignment.

NB: declaring and assigning a variable on one line is called initialization assignment.

There are two sets of comparison operators: non-strict and strict. The latter (=== and !==) never performs implicit conversions, and for this reason is generally preferred. Equality comparisons of objects only return true if both operands refer to the same object. Under all other circumstances they return false, even if the objects have the same property names and values.

Pure Functions and Side Effects

A pure function is one which doesn’t alter the values of outer-scope or global variables. Side effects refer to changes made to outer-scope or global variables from within a function.

Outer-scope variables referenced or reassigned inside of a function will have these changes reflected outside of the function. If the variables are passed into the function as arguments, however, a new, same-named variable is effectively created inside of the function. This new variable will be locally scoped, and in shadowing the outer scope variable, will prevent it from experiencing side effects.

NB: If a primitive is passed as an argument, any changes made to the argument will be confined to the function scope. However, if an object is passed as an argument, the changes will be reflected in the outer scope.

List Processing Abstractions

List processing abstractions are called on collections, and allow us to abstract (i.e., render declaractive some otherwise imperative) particular processes that can be called on lists:

|Abstraction|Use|Returns|Array Method| | — -| — -| — -| — -| |Iteration|Perform an operation on each element in an array|nothing|forEach| |Filtering/Selection|Select a subset of elements|new array|filter| |Transformation|Compute a new value from each element|new array|map| |Ordering|Rearrange elements by sorting|reference to original array|sort| |Reducing/Folding|Iteratively compute a result based on all element values|single value|reduce,reduceRight| |Interrogation|Determine whether an array's elements meet a condition|single value|every, some|

Each of these methods takes a function as an argument, which is often referred to as a callback function. The function is passed a set of optional arguments by abstraction, and may return a value that will be used by the abstraction in its next iteration over the list.

Iterate over an array with forEach, which is invoked once for each element in the array and supplies three arguments to the callback function:

  • value of current element
  • current index
  • aray being processed
['Peter', 'Paul', 'Mary'].forEach(function(name, index, array) {
console.log(name, index, array[index]);

// logs

// Peter 0 Peter
// Paul 1 Paul
// Mary 2 Mary

Filter the contents of an array with filter, which returns a new array that is a subset of the receiver array composed of those elements for which filter returns true. filter supplies the following values to its callback:

  • value of current element
  • current index
  • array being processed
// return all odd-indexed elements

['a', 'b', 'c', 'd', 'e'].filter(function(element, index, array) {
return index % 2 !== 0;

// returns ['b', 'd']

Transform an array with map, which returns a new array based on the return values of each iteration over the old array. Map is passed three arguments to the callback function:

  • value of current element
  • current index
  • array being processed
var count = [1, 2, 3, 4];

var doubled = {
return number * 2;

doubled; // [2, 4, 6, 8]

Reduce or fold an array to a single value with reduce, which takes a callback function and an optional second argument that serves as initial value. reduce supplies four arguments to the callback:

  • return value of the previous call
  • value of current element
  • current index
  • array being processed

If no initial value is provided as a second argument, then reduce effectively skips the first iteration, using the first value of the receiver array as initial value. Compare the outputs of the two calls below:

function add(previousValue, element, array) {
console.log(previousValue, element);
return previousValue + element;

var count = [1, 2, 3, 4, 5];


// 1 2
// 3 3
// 6 4
// 10 5
// 15

count.reduce(add, 0);

// 0 1
// 1 2
// 3 3
// 6 4
// 10 5
// 15

In the first call, without an initial value, the first element of the receiver (1) is used, with the second element (2) as current value, while in the second call, the initial value argument (0) is used, and the first element of the receiver (1) is current element.

Reduce returns the value returned by the final callback invocation.

Interrogation allows us to determine how many of the Array’s elements satisfy some conditon. every tells us whether every element in the array satisfies the condition, while some tells us whether at least one of the elements does. In other words, every returns true if the return value of every invocation of the callback is truthy, while some returns true if at least one invocation has a truthy return value.

Both of these methods pass three values to the callback:

  • value of current element
  • current index
  • array being processed

Perform an in-place sort (i.e., mutate the receiver array) with sort. The sorting rules are established in the callback function, which takes two arguments and returns a positive number value, negative number value, or zero, depending on their relationship:

  • a > b: positive
  • a < b: negative
  • a == b: 0
function compareLengths(s1, s2) {
length1 = s1.length;
length2 = s2.length;

if(length1 < length2) {
return -1;
} else if (length1 > length2) {
return 1;
} else {
return 0;

var strings = ['a', 'abcde', 'abc', 'ab', 'a', 'abcdefg'];
strings.sort(compareScores); // ["a", "a", "ab", "abc", "abcde", "abcdefg"]
strings; // ["a", "a", "ab", "abc", "abcde", "abcdefg"]

Launch School

Publications of the Launch School Community

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store