Jump to main content
Menu

JavaScript Programming Fundamentals

Data Types in JavaScript

Data Type Values Considerations
String Any value with quotes around it, either single, double, or backtick.

let sampleStr = "Hello World";

String objects are probably the object type you will encounter the most often.

Strings exist as primitives and automatically change to objects once a property or method is invoked.

Form fields always return their data as strings.

An empty string, '' or "" or ``, evalutes to false.

A string with at least one character in it evaluates to true.

Number Number values are 64-bit floating points, and there are also special NaN (Not a Number; can occur when doing math that combines a string and a number) and Infinity values. Both of those special values are Number objects.

Numbers never have quotes around them; that would make them a string.

let sampleNumber = 5;

Mathematical operations follow the standard PEMDAS (Parentheses, Exponents, Multiplication, Division, Addition, Subtraction) sequence.

Numbers are treated as strings under certain conditions.

If you are examining a number to evaluate true/false, 0 and NaN are false and any other number (including negative numbers) is true.

JavaScript has an isNaN() method for testing whether something is a number or not. Pass the variable you are testing as the parameter and what gets returned is either true (it is not a number) or false (it is a number). Useful when combining values, since somewhere along the line a non-numerical character could have been inserted.

Numbers exist as primitives and automatically change to objects once a property or method is invoked.

Boolean Only two values exist: true and false

Booleans never have quotes around them; that would make them a string.

let sampleBool = true;

Booleans exist as primitives and automatically change to objects as necessary.
Null The only value for this data type is null

This is not quoted; that would make it a string.

null occurs when the object or variable you are looking for does not exist.

null evaluates to false.

Undefined The only value for this data type is undefined

This is not quoted; that would make it a string.

undefined occurs when a variable is declared (e.g., let sampleVariable;) but has no value.

If a function is expecting a value to be passed to one of its parameters but no value is sent, that parameter is undefined.

undefined is also returned when you try to access an unset property or method of an object.

undefined evaluates to false.

Symbol Symbols are assigned a private and unique value. Symbols are created via the Symbol() global factory function. These are usually assigned to a variable that is then used as the property of an object, and because symbols are always unique there is no chance of the property name colliding with another property name.

ES6 (ECMAScript Version 6) introduced this primitive.

Determining what symbols are assigned as object properties is done via the Object.getOwnPropertySymbols() method, which can then be looped through.

Object Everything else is an object, including functions and nodes returned via the DOM.

If you pass the alert() method a reference to the object, the value displayed will be object or something that more specifically describes the type of object.

console.log() can also be used to output details to the console (accessed via the Inspector/Developer Tools, which are opened by hitting F12 in most cases).

Objects are unique because when we use them (comparing them, passing them, modifying them) the variable we are acting upon is just a reference to the object and not a copy of the object itself. Changes to that variable cause changes in the object being referenced.

If an object exists, it is true.

If the object does not exist, it is null and therefore false.

Variables

  • Variables are named containers for data.
  • Variables can be any of the data types (string, number, boolean, null, undefined, symbol, object). If the variable has string data, it is a String object, if it has only number data it is a Number object, etc.
  • In the case of the Object data type, the variable is a reference to that object.
  • JavaScript is loosely typed, so object types can change automatically under certain conditions:
    • When combining a string and a number using + the number is treated as a string.
    • Strings used with other mathematical operators (such as multiplication or division) are treated as numbers; if there is a letter or letters in the string the result is NaN.
  • Variables are declared (which creates a named memory location) using the let or const keyword, followed by the name you want to use for the variable (see the section on Reserved Words for words to avoid).
  • const is a constant, so the value (if the variable is a primitive) is immutable.
  • If the variable is not a primitive (for example, if the variable is an Object object), then using const means that it cannot be changed to a different object type (so an Array object cannot be changed to an Object object), but you can modify its properties / methods / values (the options depend on the object type) as much as desired.
  • Also keep in mind that variables can only start with a letter or an underscore character. An example (the variable is named x) is:
    let x;
    

    To declare multiple variables, each can be placed on its own line with let or const preceding its name, or they can share one let or const and have commas between the names:

    let x, y, z;
    
  • To initialize a variable you assign it a value. This is a good thing to do; otherwise the data type is set to undefined and that could cause issues later in the code. An example (the value assigned is the number 14) is:
    let x = 14;
    
  • To initialize multiple variables, you can also separate them by commas:
    let x = 14, y = 10, z = "yes";
    
  • Only indicate let or const when initializing or defining the variable. Subsequent uses of that variable just give the variable name.
  • Variable names are case-sensitive; the same capitalization must be used when the variable is initialized / defined as well as when it is used later.
  • All-lowercase or camelCase (capitalizing the first letter of every word after the first word, such as userName and validateFormData) are recommended.
  • Do not have spaces in variable names; underscores are fine.
  • ES3 (ECMAScript Version 3) does not support let or const and instead uses var in all cases. So if you are seeing var, the code is using an earlier version of the ECMAScript / JavaScript standard.
  • In practice, const is the preferred approach. Code review tools will favor its usage and employers and fellow programmers will expect you to use it, unless the situation calls for let.

Scope

  • ES6 has two scopes:
    • Block scope
    • Global scope
  • let and const both use block scope, which means they are bound to the innermost block that contains them.
  • Functions defined with the function keyword are in the global scope, which means they are always available.

Operators

Operators are used in various ways, including combining strings together, performing mathematical operations, and determining whether a specific condition has been met.

Operator Usage Code Example
= Simple assignment; not equivalence. const greet = 'hello world';
+ Concatenate; joins together two strings.

Has a different impact when applied to numbers.

console.log("The value of x is " + x + " in this lecture.");
+ Addition const number1 = 10;
const number2 = 5;
const sum = number1 + number2;
console.log("The sum is " + sum);
+ Unary plus - converts operand into a number or NaN if that is not successful. let x = "25";
console.log("x as a number is:");
console.log(+x);
- Subtraction

Can only be used with numbers.

const number3 = 10;
const number4 = 5,
const diff = number3 - number4;
console.log("The difference is " + diff);
- Unary negation - converts operand into a number or NaN if that is not successful and then negates it. let x = "-25";
console.log("x as a number with unary negation is:");
console.log(-x);
* Multiplication

Can only be used with numbers.

const number5 = 10;
const number6 = 5;
const result = number5 * number6;
console.log("Multiplying the numbers totals " + result);
/ Division

Can only be used with numbers.

const number7 = 10;
const number8 = 5;
const result2 = number7 / number8;
console.log("Dividing the numbers results in " + result2);
% Modulo - the remainder after division.

Can only be used with numbers.

const number9 = 11;
const number10 = 4;
const modulo = number9 % number10;
console.log("The modulo is " + modulo);
++ Increment; useful in loops. See for loops for an example.
-- Decrement; useful in loops. for (let i=7; i>0; i--) {
console.log(i);
}
+= Concatenate-by-value / Add-by-value

For strings: Concatenates the right operand to the end of the left operand.

For numbers: Adds the value of the right operand to the left operand.

When numbers and strings are both used, the numbers are converted to strings.

let fullName = "Learning to ";
fullName += "Code";
console.log("The site name is " + fullName);
-= Compound assignment and subtract-by-value. let number11 = 11;
number11 -= 3;
console.log("The modified value is " + number11);
*= Compound assignment and multiply-by-value. let number12 = 15;
number12 *= 3;
console.log("The modified value is " + number12);
/= Compound assignment and divide-by-value. let number13 = 15;
number13 /= 3;
console.log("The modified value is " + number13);
%= Compound assignment and modulo-by-value. let number14 = 16;
number14 %= 3;
console.log("The modified value is " + number14);
== true if these are equivalent; not assignment

Use === rather than ==, because == changes operand type to try to make a match. This leads to unexpected results.

Each of these is true, which is worrisome:

0 == '0'
null == undefined
' \t\r\n ' == 0
false == '0'

!= true if these are not equivalent.

Use !== rather than !=, for the same reason that === should be used rather than ==.

if (x != 5) {}
=== true if these are equivalent; no data type conversion occurs. See the conditional logic section for examples.
!== true if these are not equivalent and/or not the same data type. See the conditional logic section for examples.
> true if left operand is greater than right operand. See the conditional logic section for examples.
>= true if left operand is greater than or equal to the right operand. See the conditional logic section for examples.
< true if left operand is less than right operand. See the conditional logic section for examples.
<= true if left operand is less than or equal to the right operand. See the conditional logic section for examples.
&& Logical AND; true if both operands are true. See the conditional logic section for examples.
|| Logical OR; true if either operand is true. See the conditional logic section for examples.
! Logical NOT; true if the operand is false. See the conditional logic section for examples.

Conditional Logic Using if, else if, and else

  • These are conditionals because one result or another will occur if a given condition is met or not met.
  • The key determination is whether a test condition evaluates to true or false.

if Conditionals

  • A simple if conditional will test whether a single condition is met (if it is true), in which case the indicated result occurs.
  • If the condition is not met (if it is false) then nothing occurs.

Syntax for if Conditional

if (test condition) {
  instructions executed if test condition evaluates to true
}

if Conditional Example

const response1 = "yes";
if (response1 === "yes") {
  console.log("The answer is " + response1);
}

Note: To evaluate equivalence === is used rather than = (which is for assignment).

Expanding into if - else Conditionals

  • In this approach there is also a result if the condition is not met (if the test condition evaluates to false).

Syntax for if - else Conditional

if (test condition) {
  instructions executed if test condition evaluates to true
}
else {
  result if test condition evaluates to false; serves well as the default
}

if - else Conditional Example

const response2 = "maybe";
if (response2 === "yes") {
  console.log("The answer is " + response2 + ".");
}
else {
  console.log("The answer is not yes.");
}

Multiple Branches: if, else if, and else

  • In this approach there are a variety of possible outcomes (as many possibilities as are needed).
  • As soon as a condition evaluates to true, the conditional sequence is exited (subsequent conditionals are not checked).
  • Having the else is optional.

Syntax for Multiple Branches

if (first test condition) {
  instructions executed if first test condition is true
}
else if (second test condition) {
  next to be evaluated if first test condition was false;
  stops here and executes this code if second test condition is true
}
else if (third test condition) {
  next to be evaluated if second test condition was false;
  stops here and executes this code if third test condition is true
}
else {
  result if all other test conditions are false
}

Multiple Branches Example

const response3 = "no";
if (response3 === "yes") {
  console.log("The answer is yes.");
}
else if (response3 === "maybe") {
  console.log("The answer is maybe.");
}
else if (response3 === "no") {
  console.log("The answer is no.");
}
else {
  console.log("The answer is unknown.");
}

Nested Conditionals

  • Conditionals can also have other conditionals nested inside them.
  • This has the most potential for syntax errors (usually due to missing brackets).

Syntax for Nested Conditionals

if (first test condition) {
   if (second test condition) {
      result only occurs if both first and second test conditions are true
   }
   else if (third test condition) {
      result only occurs if first test condition is true, second test condition is false, and third test condition is true
   }
   else {
      result only occurs if first test condition is true and all subsequent test conditions are false
   }
}

Nested Conditionals Example

const answer1 = 25;
if ((answer1 > 10) && (answer1 < 30)) {
   if (answer1 <= 15) {
     console.log("The first answer is less than or equal to 15.");
   }
   else if (answer1 <= 20) {
     console.log("The first answer is less than or equal to 20.");
   }
   else {
     console.log("The first answer is between 20 and 30.");
   }
}

Considerations with Boolean Operators

  • JavaScript uses short-circuit evaluation when dealing with boolean / logical operators.
  • In && (AND) setups if the first operand is false then the second operand is ignored, because the overall result would have to be false regardless of how subsequent operands evaluate.
    • This is also the case for (a && b && c).
    • If a is false then the others would not be evaluated.
    • If a is true and b is false, then c is not evaluated.
  • In the case of || (OR), if the first operand is true then the overall result is true, so the additional operands are not evaluated.
    • One interesting variation for || is in the area of assignment.
    • If you have const x = a || b; and the a variable evaluates to false, then x is automatically assigned to the value of the b variable.

The Ternary Operator

  • The ternary operator offers a more streamlined approach to if - else setups.
  • The ternary operator uses a ? to separate a condition to be evaluated from two outcomes, which are separated by the : character.

Syntax for Ternary Operator

// code execution
(expression) ? true expression result : false expression result;

// assignment
const x = (expression) ? value if expression is true : value if expression is false;

The ternary (triple) name comes from the three sections:

  1. Section preceding the ?
  2. Section between ? and :
  3. Section to the right of :

Ternary Operator Example 1: Assignment

const ternary_ex1 = true;
const ternary_result1 = (ternary_ex1) ? 'it was true' : 'it was false';
console.log(ternary_result1);

Ternary Operator Example 2: Code Execution

const ternary_ex2 = 0;
ternary_ex2 ? console.log('it was true') : console.log('it was false');

The switch() Control Structure

  • While the ternary operator works well for a straightforward true/false (if/else) situation, the switch control structure is ideal as a replacement for if / else if / else if / else if / else if / else if / else if / else if / else situations.
  • In other words, it is ideal for lengthy conditional logic situations.
  • The parameter passed to switch is the variable whose value is being checked.
  • Each condition you are checking (each value you are checking) is a case.
  • An optional default can be specified; this is equivalent to else because it is what happens if none of the case values match.
  • The use of break saves time by stopping the rest of the case checking after that point.
  • Strict equivalence (===) is used when matching value to case, so keep that in mind.

switch() Code Example

const the_answer = 'yes';
switch (the_answer) {
  case 'no' : console.log('Not quite'); break;
  case 'maybe' : console.log('Getting closer'); break;
  case 'yes' : console.log('Correct!'); break;
  default : console.log('Nowhere close');
}

Array Objects

  • While regular variables can only hold one value at a time (most languages refer to these as scalar variables), an array object is a special type of variable that can hold multiple values. Any data type can be stored.
  • By default, the content within an array is indexed (organized) numerically and the sequence always begins with the number 0 (position 0 is the first item in the array).
  • There is no upper bound to the numerical index.
  • It is possible to index based on strings and to have multi-dimensional (nested) arrays, which is covered in a separate lecture.
  • If you skip some of the positions in the sequence (not giving those positions a value) they have the undefined data type.
  • JavaScript supports dynamic array addressing, which means that arrays can be increased or decreased in size at any time.
  • There are multiple ways to create and populate Array objects; we will focus on the most efficient way (referred to as the array literal). An example is:
    const topics = ['Topic 1', 'Topic 2'];
    
  • Accessing / adding / editing items in the array continues to use the [] syntax.
  • If we wanted to add 'Topic 3' we would specify:
    topics[2] = 'Topic 3';
    
  • Array objects have a length property that reflects the highest numerical index assigned. Non-numerical indexes do not count in the length.
  • There are a variety of Array object methods covered in a separate article.

for and for-of Loops

  • A for loop executes a piece of code repeatedly, until a pre-set condition evaluates to false.
  • These are extremely useful when iterating through all the items in an array object and typically use the length of the array to determine when to stop. This works just fine in most situations.

for loop Syntax

for (initial value; test condition; update value) {
  JavaScript statements to execute in each loop
}

for Loop Code Example

console.log('HTML Headings from Largest to Smallest');
for (let size = 1; size < 7; size++) {
  console.log('<h' + size + '>');
}

for Loop Considerations

  • Always make sure that the code within the loop is moving toward the point where the test condition is false. Usually this involves incrementing (++) or decrementing (--) a value. If this is not being done you very likely have an infinite loop.
  • These loops run faster when the test condition is a fixed value, such as a set number. Otherwise each time the loop occurs the value needs to be calculated / checked again. If there are thousands of items in the array this can make a noticeable impact on performance.
  • If you are looping through an array, and your loops are not modifying the number of items in the array, then assigning the length of the array to a variable and checking against that number will speed up the loop performance.

for-of Loops

  • With ES6 we also have a for-of loop.
  • This loop variation eliminates the need for a counter or something else to evaluate true/false, in order for the loop to continue. Instead this goes through every item in the array (or other collection / list).
  • It still supports break to leave the loop and continue to jump to the next loop iteration.

for-of loop Syntax

for (drop-in variable of dataset) {
  JavaScript statements to execute in each loop
}

for-of Loop Code Examples

console.log('HTML Headings from Largest to Smallest');
for (const size of ['1', '2', '3', '4', '5', '6']) {
  console.log('<h' + size + '>');
}

If you need the index of the array element, there is also an entries() method:

console.log('HTML Headings from Largest to Smallest');
for (const [index, size] of ['1', '2', '3', '4', '5', '6'].entries()) {
  console.log(index + ': <h' + size + '>');
}

Object Literals

  • The object literal syntax establishes a new Object object with the variable name you indicate.
  • Properties and methods (along with their values) are represented in a name : value pattern, with each one (except for the last name / value pair) being followed by a comma.
  • The object literal syntax uses the {} (curly braces), which distinguishes it from other literals, such as the array literal that uses [] (square braces).
  • What makes the object literal so useful is that it prevents the global namespace from being cluttered with too many variable names (which raises the chances of a collision between different sets of code). Here is a quick example:
    const sampleObject = {
      maxValue : 14,
      welcome : 'Hello world',
      doSomething : function() {},
      theData : [3,5,7,8]
    }
    
  • To call the doSomething() method is as simple as specifying sampleObject.doSomething();
  • The array object is accessed via sampleObject.theData[0] (or whatever position you wish to access).
  • The only potential collision in the global namespace is with sampleObject, so hopefully no other code being called for the page used that name for one of their global variables.
  • Edits to the Object (including adding methods / properties) can be made from anywhere in the code, such as outside of the object literal:
    sampleObject.farewell = 'Goodbye world';
    
  • There is also a delete method in JavaScript that is used to remove properties and methods, such as:
    delete sampleObject.maxValue;
    

Functions

  • Functions typically contain multiple JavaScript statements (although they could just contain one statement) and can be passed parameters (also called arguments), which then modify the outcome.
  • Parameters are block scope variables that are automatically declared when the function is called.
  • Functions are defined once and can be called an unlimited number of times.
  • Functions can call other functions and functions can even be passed to other functions as a parameter. This is important; you will often want one function to pass data to another function or to trigger multiple other functions.
  • Functions can also be nested. Nested functions can access the block scope variables of their parent function, but the parent function cannot access the block scope variables of the child function. This is referred to as a closure.
  • Like variables, the name given to a function is case-sensitive so the same capitalization must always be used. All-lowercase or camelCase style are recommended.
  • The basic syntax for a function (items that would need to be defined are in italics) is:
    function name() {
      JavaScript statements
    }
    
  • Note that the () following the name can be left empty if no values are passed to the function. If values were passed the parameter name(s) would be noted in the parentheses; multiple parameters would be separated by commas.
  • Regardless of the parameters you pass to the function, every function is also passed two additional parameters:
    1. arguments[] - This array-like object contains every parameter you passed, regardless of whether the function was expecting to receive it. This object has a length property that can be used in a for loop that cycles through all the parameters passed (the first item is arguments[0]).
    2. this - A reference to the object that called the function

Function Code Example

function tracker(author, topic) {
  console.log(topic + ' article by ' + author + '.');
}
tracker('Jason W', 'JavaScript');

Additional Function Details and Variations

  • Functions always return (send back) a value, which is undefined unless you set it. You can also specify the return keyword, followed by the value being sent back. Be sure to start this value on the same line as return.
  • If you simply want to stop the function, you can specify return; at any point in the code.
  • Within the context of a custom Object that we create, these functions are the methods of that object.
  • In ES6 we can assign default values to parameters; these are used if a value is not passed.
  • ES6 also introduced arrow functions.
    • Arrow functions change what this references inside the function. In an arrow function, this always references the object containing the function.
    • Outside of arrow functions, this refers to whatever invoked the function.

Function with Defaults Example

function tracker(author='JW', topic='Coding') {
  console.log(topic + ' article by ' + author + '.');
}
tracker();

Arrow Function Example

const tracker = (author='JW', topic='Coding') => {
  console.log(topic + ' article by ' + author + '.');
}
tracker();

Classes

  • Classes in ES6 provide the standard object-oriented experience familiar to other object-oriented languages.
  • They are defined with the class keyword, contain a constructor method, other methods, and are invoked using the new keyword.
  • ES6 classes also support inheritance (one class can extend another class), but only one level and one parent. The super keyword is used to access the parent class.
  • Read more about ES6 classes

class Code Example

class Tracker {

  constructor(author, topic) {
    this.author = author;
    this.topic = topic;
  }

  output() {
    return this.topic + ' article by ' + this.author + '.'
  }

}

const articleTrack = new Tracker('Jason W', 'JavaScript');
console.log(articleTrack.output());

Template Literals

  • Template literals are another option in ES6 for working with strings.
  • They are enclosed in backticks.
  • These can be much easier to read (and write) than a concatenated sequence, because ${} indicates what to interpolate.

Template Literal Code Example

const piVal = 3.14;
const str = `The first 3 digits of pi are ${piVal}`;
console.log(str);

Troubleshooting Tools & Techniques

One of the realities of programming is that errors will occur. Thankfully, there are a variety of options available for troubleshooting these errors.

Developer Tools Console

  • Press F12 when your browser window has focus to launch the Developer Tools. It will have a tab for 'Console'.
  • Errors pile up in the console, so be sure to clear it before you run your code. You do not want to spend hours trying to track down an old error that has long since been fixed.

console.log()

  • As seen in the examples, this is an unobtrusive way to output values for troubleshooting purposes.
  • Reload the console before each run, if you're troubleshooting the same code.

alert()

  • By inserting alert() statements at various points in your code, you can determine what value a variable has at a given point, or even just determine that a function is being called.
  • If your alert() never shows, you know you have a problem with that function getting called.

Web Developer Toolbar

  • This is a Firefox, Chrome, Edge, and Opera extension. The extension has a variety of useful tools, including the ability to disable JavaScript entirely and also to quickly bring up the JavaScript console (and alert you that errors have occurred).
  • The toolbar can be downloaded from https://chrispederick.com/

try/catch

  • try/catch is used in both code debugging and also in production code to recover gracefully from errors (and perhaps branch code in a different direction).
  • If the code inside of try {} throws any error, that error is passed to the catch() {} portion and the code inside of catch() {} executes. If no error occurred, the catch() {} is skipped.
  • Consider the following try/catch example, which throws an error because === is used rather than = and the variable is not defined:
    try {
      myVariable === true;
    }
    
    catch(error) {
      alert(error);
    }
    

Reserved Words

  • Reserved words should not be used for variables, functions / methods, or properties since they have other meanings in JavaScript (or have been reserved for future use).
  • Variations (even slight changes) will make the word permissible.
  • If a special syntax style is used the reserved word can be used, but we won't worry about that.
  • To quickly search for a word in the list, use Control + F ('Find in Page')
  • The reserved words are:

    abstract, boolean, break, byte, case, catch, char, class, const, continue, debugger, default, delete, do, double, else, enum, export, extends, final, finally, float, for, function, goto, if, implements, import, in, instanceof, int, interface, long, native, new, package, private, protected, public, return, short, static, super, switch, synchronized, this, throw, throws, transient, try, typeof, var, void, volatile, while, with

  • Also avoid words used for core objects (such as Array), properties, or methods, or using null, undefined, true, or false due to confusion with data types. Even if there are no errors, you will almost certainly confuse the next person to work with your code.

Strict Mode

  • Strict mode is triggered by specifying either:
    'use strict';
    

    or

    "use strict";
    
    at the start of your JavaScript file, before any other statements.
  • That will put the entire file into strict mode. Alternately, this can be the first instruction inside a function to put that function into strict mode.
  • This mode causes more errors to show in the console (helpful for improving code quality) and can also improve performance.
  • Read more about strict mode