You already know the grammar of the language: statements, blocks, valid names and strict mode. Now for the content: the data. Programming is, fundamentally, about storing information, transforming it and displaying it. In this lesson you will learn to create variables with let and const, you will understand why var belongs to the past, and you will go through every primitive data type in JavaScript. By the end you will be able to model each field of a Nómada Tasks task precisely, using the right type in every case.

Contents

  1. What a variable is
  2. Declaring variables: let and const
  3. var and why it is discouraged
  4. Dynamic typing and the typeof operator
  5. The string type: text
  6. The number type: numbers
  7. The boolean type: true or false
  8. undefined and null
  9. symbol and bigint
  10. Primitives versus references
  11. Modeling a Nómada Tasks task
  12. Common Mistakes and Tips
  13. Exercises
  14. Conclusion

  1. What a variable is

A variable is a name associated with a value stored in memory. The usual image is a labeled box: the label is the name and the value is inside.

const assignee = 'Marta';

Three pieces:

Piece Function
const The declaration keyword: it creates the variable
assignee The identifier: the name you will use it by
'Marta' The value that is stored

From that line onward, writing assignee anywhere below is the same as writing 'Marta'.

It is important to understand that the variable is not the value: it is a named reference. You can change what it holds (if you declared it with let) without changing its name.

  1. Declaring variables: let and const

Modern JavaScript offers two ways to declare variables.

2.1 const: the value is not reassigned

const assignee = 'Iván';
// assignee = 'Lucía'; // TypeError: Assignment to constant variable.

Two rules for const:

  1. You have to give it a value when you declare it. const x; is a SyntaxError.
  2. It cannot be reassigned afterwards.

2.2 let: the value can change

let status = 'pending';
console.log(status); // pending

status = 'in-progress';
console.log(status); // in-progress

status = 'done';
console.log(status); // done

let can be declared without an initial value; in that case the variable is undefined until you assign something to it:

let nextAssignee;
console.log(nextAssignee); // undefined

nextAssignee = 'Lucía';
console.log(nextAssignee); // Lucía

2.3 Which one to use

The rule is simple and has no practical exceptions: use const by default; use let only when you know the value is going to change.

Why? Because const communicates intent. When someone reads const dueDate = ..., they know immediately that the value will not change anywhere in the function. It is free information that reduces the mental load of reading code.

// A task's id and title do not change while we are processing it
const id = 1;
const title = 'Redesign the multipurpose room';

// The status does change over the life of the task
let status = 'in-progress';

2.4 A crucial nuance about const

const does not mean "the value is immutable". It means "the variable cannot be reassigned". If the value is an object or an array, its contents can still be modified:

const tags = ['design', 'space'];

tags.push('urgent');       // Allowed: we are modifying the contents
console.log(tags);         // ['design', 'space', 'urgent']

// tags = ['something else']; // TypeError: cannot be reassigned

This confuses a lot of people. The explanation is in section 10 (primitives versus references) and it is developed further in Module 4.

  1. var and why it is discouraged

Before ES2015 there was only var. You will find it in old code and in outdated tutorials, so it is worth knowing why it was abandoned.

3.1 Problem 1: function scope, not block scope

function reviewTasks() {
  if (true) {
    var message = 'With var';
    let notice = 'With let';
  }
  console.log(message); // 'With var' — it escapes the block
  // console.log(notice); // ReferenceError — it stays inside
}

var ignores braces: it only respects the boundaries of a function. let and const respect any block, which is the intuitive behavior.

3.2 Problem 2: it allows redeclaration

var assignee = 'Marta';
var assignee = 'Iván'; // Allowed, without any warning

let hours = 8;
// let hours = 6; // SyntaxError: Identifier 'hours' has already been declared

Redeclaring by accident in a long file is a silent way to lose data. let warns you.

3.3 Problem 3: confusing hoisting

console.log(withVar);  // undefined  (it does not fail, but it misleads)
var withVar = 'value';

// console.log(withLet); // ReferenceError: Cannot access 'withLet' before initialization
let withLet = 'value';

With var you get undefined instead of an error, which hides the real problem. With let you get a clear error. The mechanism is explained in Hoisting and the Execution Context.

3.4 Comparison table

Characteristic var let const
Scope Function Block Block
Can be reassigned Yes Yes No
Can be redeclared Yes No No
Use before declaration undefined ReferenceError ReferenceError
Requires an initial value No No Yes
Creates a property on the global object Yes No No
Recommended today No Yes, if it changes Yes, by default

Conclusion: do not write var in new code. You only need to recognize it when you see it.

  1. Dynamic typing and the typeof operator

JavaScript is dynamically typed: variables have no type, values do. The same variable can hold values of different types throughout the program.

let value = 'high';   // now it holds text
value = 12;           // now a number
value = true;         // now a boolean

It is flexible, but also dangerous: nothing warns you if a variable ends up holding something other than what you expected.

To find out what type a value has, there is the typeof operator:

console.log(typeof 'Marta');    // 'string'
console.log(typeof 12);         // 'number'
console.log(typeof true);       // 'boolean'
console.log(typeof undefined);  // 'undefined'
console.log(typeof Symbol());   // 'symbol'
console.log(typeof 10n);        // 'bigint'
console.log(typeof {});         // 'object'
console.log(typeof []);         // 'object'  ← an array is also 'object'
console.log(typeof null);       // 'object'  ← the famous historical bug!

The last two lines deserve attention:

  • typeof [] returns 'object' because in JavaScript an array is a special kind of object.
  • typeof null returns 'object' because of a bug in the very first implementation back in 1995 that has never been fixed, because fixing it would break existing code. It is the historical scar we mentioned in the first lesson.

4.1 The map of types

JavaScript has seven primitive types and one reference type (object, which covers arrays, functions, dates and so on).

flowchart TD
    T["Data types in JavaScript"]
    T --> P["Primitives<br/>(immutable value)"]
    T --> O["Objects<br/>(reference)"]
    P --> S["string"]
    P --> N["number"]
    P --> B["boolean"]
    P --> U["undefined"]
    P --> NU["null"]
    P --> SY["symbol"]
    P --> BI["bigint"]
    O --> OB["object · array · function · Date..."]

  1. The string type: text

A string is a sequence of characters: names, titles, statuses, dates in text form.

5.1 The three ways of writing text

const withSingles = 'Redesign the multipurpose room';
const withDoubles = "Redesign the multipurpose room";
const withTemplate = `Redesign the multipurpose room`;

Single and double quotes are equivalent. The majority convention in JavaScript is to use single quotes, and to keep double quotes for when the text contains an apostrophe:

const note = "Marta says the workshop is not ready";
const other = 'Marta says the workshop is not ready';
const withApostrophe = "Marta's workshop is not ready";  // more comfortable with doubles

You can also escape a character with a backslash:

const escaped = 'Marta\'s workshop is not ready';

5.2 Template literals: the modern way

Template literals use backticks (`) and give you two superpowers.

Superpower 1: interpolation with ${}. You can insert the value of any expression inside the text:

const assignee = 'Iván';
const estimatedHours = 12;

// The old way: concatenation
const oldWay = 'Task for ' + assignee + ': ' + estimatedHours + ' hours';

// The modern way: a template literal
const modernWay = `Task for ${assignee}: ${estimatedHours} hours`;

console.log(modernWay); // Task for Iván: 12 hours

It reads far better, and the mistakes with forgotten spaces between quotes disappear.

Any expression can go inside ${}, not just a variable:

const ivanHours = 12;
const luciaHours = 8;
console.log(`Combined workload: ${ivanHours + luciaHours} hours`); // 20 hours

Superpower 2: real line breaks. The text is written as it is, across several lines:

const summary = `Task: Redesign the multipurpose room
Assignee: Iván
Priority: high`;

console.log(summary);

With ordinary quotes you would have to use \n, which reads far worse.

5.3 Basic properties and methods

Even though string is a primitive, JavaScript lets you use properties and methods on it:

const title = 'Redesign the multipurpose room';

console.log(title.length);          // 30 — number of characters
console.log(title.toUpperCase());   // REDESIGN THE MULTIPURPOSE ROOM
console.log(title.includes('room')); // true
console.log(title[0]);              // 'R' — first character (position 0)

One fundamental detail: strings are immutable. No method modifies the original; they all return a new one.

const original = 'pending';
const inUppercase = original.toUpperCase();

console.log(original);     // 'pending' — untouched
console.log(inUppercase);  // 'PENDING' — a new string

  1. The number type: numbers

JavaScript has a single numeric type: number. It does not distinguish between integers and decimals the way other languages do.

const estimatedHours = 12;      // integer
const actualHours = 12.5;       // decimal
const deviation = -0.5;         // negative
const almostZero = 1.5e-4;      // scientific notation: 0.00015
const withSeparator = 1_000_000; // the underscore improves readability

6.1 Special numeric values

There are three values that are of type number but are not ordinary numbers:

Value Means How it shows up
Infinity Positive infinity 1 / 0, or a number that is too large
-Infinity Negative infinity -1 / 0
NaN Not a Number: a non-numeric result 'high' * 2, Number('hello')
console.log(10 / 0);            // Infinity
console.log('high' * 2);        // NaN
console.log(typeof NaN);        // 'number' ← yes, NaN is of type number

NaN has a baffling property: it is not equal to itself.

console.log(NaN === NaN); // false

That is why the Number.isNaN() function is used to detect it:

const hours = Number('twelve'); // NaN
console.log(Number.isNaN(hours)); // true

NaN is the typical result of a data error: someone put text where you expected a number. Seeing it in the console almost always means "check where that value came from".

6.2 Floating-point precision

This is one of every programmer's first shocks:

console.log(0.1 + 0.2);           // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3);   // false

This is not a JavaScript bug. Numbers are stored in binary following the IEEE 754 standard, and some decimals (such as 0.1) have no exact binary representation, just as 1/3 has no exact decimal representation. Almost every language behaves the same way.

Practical solutions:

const total = 0.1 + 0.2;

// Round to as many decimals as you need
console.log(total.toFixed(2));         // '0.30' (careful: it returns a string)
console.log(Number(total.toFixed(2))); // 0.3 (a number)

// Compare with a tolerance
console.log(Math.abs(total - 0.3) < Number.EPSILON); // true

Professional tip: for money, do not use decimals. Store cents as integers. In Nómada Tasks we will work with hours, where half a point of precision is more than enough.

6.3 Useful math operations

const hours = 12.7;

console.log(Math.round(hours));  // 13 — normal rounding
console.log(Math.floor(hours));  // 12 — down
console.log(Math.ceil(hours));   // 13 — up
console.log(Math.max(12, 8, 6)); // 12
console.log(Math.min(12, 8, 6)); // 6

  1. The boolean type: true or false

A boolean can only be true or false. It is the type of decisions.

const isCompleted = false;
const isUrgent = true;

Booleans usually come out of comparisons:

const estimatedHours = 12;
const isLongTask = estimatedHours > 8;

console.log(isLongTask);        // true
console.log(typeof isLongTask); // 'boolean'

Naming convention: booleans get a name that reads as a statement that is either true or false: isUrgent, isCompleted, hasTags, canBeEdited. Compare if (isCompleted) with if (completed): the first one reads by itself.

  1. undefined and null

Both represent the "absence of a value", but they are not the same, and the difference is conceptual:

undefined null
Meaning "No value has been assigned" "Deliberately empty"
Who sets it JavaScript, automatically You, explicitly
typeof 'undefined' 'object' (historical bug)
When it appears A variable declared without a value, a parameter that was not passed, a property that does not exist When you decide that something is empty
// undefined: JavaScript has nothing to put there
let nextReviewer;
console.log(nextReviewer); // undefined

// null: we are declaring that no assignee has been set
let assignee = null;
console.log(assignee); // null

The practical distinction in Nómada Tasks: if a task does not have an assignee yet, we will use null (we know it is unassigned). If we look up a field that does not even exist, we will get undefined (there is no information).

console.log(null == undefined);  // true  ← loose comparison
console.log(null === undefined); // false ← strict comparison

That contrast is the doorway into the next lesson; there you will see why it happens.

  1. symbol and bigint

The two remaining primitives are specialized. It is enough that you know they exist.

symbol (ES2015) creates unique, unrepeatable identifiers, used above all as property keys that will not collide with others:

const key1 = Symbol('id');
const key2 = Symbol('id');
console.log(key1 === key2); // false — every symbol is unique

bigint (ES2020) lets you work with integers larger than number can represent exactly. It is written by adding n at the end:

const huge = 9007199254740993n;
console.log(typeof huge); // 'bigint'

It is useful in cryptography or for very large identifiers. We will not need it in Nómada Tasks: task ids will be ordinary numbers.

  1. Primitives versus references

This is the most important idea in the lesson and the one that prevents the most bugs in the long run.

Primitive values are copied by value. When you assign one primitive variable to another, the content is copied: you end up with two independent values.

let ivanHours = 12;
let luciaHours = ivanHours; // the value 12 is copied

luciaHours = 8;

console.log(ivanHours);  // 12 — unaffected
console.log(luciaHours); // 8

Objects and arrays are copied by reference. When you assign them, the content is not copied: what is copied is the address where the content lives. Both variables point to the same place.

const ivanTags = ['design', 'space'];
const tagsCopy = ivanTags; // the reference is copied, not the list

tagsCopy.push('urgent');

console.log(ivanTags); // ['design', 'space', 'urgent'] ← it changed too!
console.log(tagsCopy); // ['design', 'space', 'urgent']

This always comes as a surprise the first time. The usual analogy: a primitive is like photocopying a document (two independent sheets of paper); an object is like handing out the address of a house (two people with the same address walk into the same house).

flowchart TD
    subgraph PR["Primitives: copied by value"]
        A1["ivanHours → 12"]
        A2["luciaHours → 12"]
        A1 -.->|independent copy| A2
    end
    subgraph RE["Objects: copied by reference"]
        B1["ivanTags"] --> C["['design','space','urgent']"]
        B2["tagsCopy"] --> C
    end

And this also explains the behavior of const we saw earlier: const protects the reference, not the content it points to.

How to really copy objects (shallow and deep copies) is covered in JSON and Copying Objects. For now, hold on to the idea: primitives, a copy; objects, a shared reference.

  1. Modeling a Nómada Tasks task

Let's apply everything we have learned. These are the fields of a Taller Nómada task with the type that suits each one:

Field Type Why that type Example
id number A sequential numeric identifier 1
title string Free text 'Redesign the multipurpose room'
assignee string (or null) The person's name; null if unassigned 'Iván'
priority string One of three fixed values 'high'
status string One of three fixed values 'in-progress'
tags array of string Zero or more tags ['design', 'space']
estimatedHours number A quantity, decimals allowed 12
dueDate string An ISO date 'yyyy-mm-dd': it sorts correctly as text '2026-09-30'

And here is the code, using only what we have seen in this lesson:

'use strict';

// --- Taller Nómada task 1 -----------------------------------------
const id = 1;                                    // number
const title = 'Redesign the multipurpose room';  // string
const assignee = 'Iván';                         // string
const priority = 'high';                         // string
let status = 'in-progress';                      // string (it will change: let)
const tags = ['design', 'space'];                // array of strings
const estimatedHours = 12;                       // number
const dueDate = '2026-09-30';                    // ISO string

// A derived value, calculated from the others
const isLongTask = estimatedHours > 8;           // boolean

// We do not know yet who will review it
const reviewer = null;                           // null: empty on purpose

// A summary with template literals
console.log(`[${id}] ${title}`);
console.log(`Assignee: ${assignee} · Priority: ${priority}`);
console.log(`Status: ${status} · ${estimatedHours} h · Due: ${dueDate}`);
console.log(`Tags: ${tags.join(', ')}`);
console.log(`Long task? ${isLongTask}`);
console.log(`Assigned reviewer: ${reviewer}`);

Output:

[1] Redesign the multipurpose room
Assignee: Iván · Priority: high
Status: in-progress · 12 h · Due: 2026-09-30
Tags: design, space
Long task? true
Assigned reviewer: null

Design decisions worth understanding:

  • status is a let because a task goes from 'pending' to 'in-progress' and then to 'done'. Everything else is const.
  • dueDate is a string, not a Date object. The ISO format yyyy-mm-dd has a very practical property: sorted alphabetically it matches chronological order. That simplifies the work enormously.
  • isLongTask is not data: it is a calculation. It is derived from estimatedHours. It is not stored as a field of the task.
  • reviewer is null, not undefined. We are stating that there is no reviewer, not that we know nothing about the matter.

Right now these are eight separate variables, which is awkward once you have three tasks to handle. In Module 4 you will learn to group them into an object, which is how they will really live in Nómada Tasks.

Common Mistakes and Tips

Common mistakes

  • Believing that const freezes the contents. It protects the variable against reassignment, not the object it points to.
  • Using let by default. Always start with const and switch to let only when your mental compiler says "this changes".
  • Confusing the number 12 with the string '12'. They look the same in the console but behave very differently: 12 + 12 is 24, '12' + '12' is '1212'. The next lesson is devoted to this.
  • Comparing decimals with ===. 0.1 + 0.2 === 0.3 is false. Use toFixed or a tolerance.
  • Comparing against NaN. NaN === NaN is false. Use Number.isNaN().
  • Using null and undefined interchangeably. undefined is set by JavaScript; null is set by you. Keep the distinction and your code will say more.
  • Copying an array and expecting independence. const copy = original; copies nothing: it shares the same list.

Tips

  • const by default, let when it changes, var never.
  • Use template literals for any text that combines variables. Fewer mistakes and better readability.
  • Name booleans as statements of fact: isUrgent, isDone, hasReviewer.
  • Use typeof whenever something behaves strangely. A console.log(typeof x, x) solves half of all mysteries.
  • Store dates in the ISO format 'yyyy-mm-dd'. They sort themselves and read the same in any country.
  • Be careful with decimals in money and percentages. Round when displaying, not when calculating.

Exercises

Exercise 1: Choose the right type

For each piece of Taller Nómada data, state the most suitable type, whether you would use let or const, and write the line of code:

  1. A task's identifier, which is 7 and will not change.
  2. The number of pending tasks, which will vary.
  3. Whether the screen-printing workshop is booked for Thursday.
  4. The name of the person who will review the task, not yet decided.
  5. The team's maximum weekly hours: 40, a fixed configuration value.
  6. The hours spent so far, which are 3.5 and will increase.

Exercise 2: Predict the output

Without running the code, write what each line prints and explain why:

let ivanHours = 12;
let luciaHours = ivanHours;
luciaHours = 8;
console.log(ivanHours, luciaHours);          // A

const tags = ['design'];
const copy = tags;
copy.push('urgent');
console.log(tags.length);                    // B

console.log(typeof null);                    // C
console.log(typeof NaN);                     // D
console.log(0.1 + 0.2 === 0.3);              // E

const title = 'Review the invoices';
title.toUpperCase();
console.log(title);                          // F

let reviewer;
console.log(reviewer === null);              // G

Exercise 3: A complete card with template literals

Write a script that declares, with the right type and keyword, every field of this task:

  • id: 4
  • Title: Set up the autumn exhibition
  • Assignee: Lucía
  • Priority: medium
  • Status: pending (it will be able to change)
  • Tags: setup, event
  • Estimated hours: 7.5
  • Due date: 2026-11-05

Then calculate and display:

  1. A header with the id and the title, using a template literal.
  2. A line with the assignee, the priority and the status.
  3. A boolean isLongTask (more than 8 hours) displayed as text.
  4. The number of tags.
  5. The title in uppercase, then checking that the original is still untouched.
  6. The type of estimatedHours and of dueDate, using typeof.

Solutions

Exercise 1

# Type Keyword Code
1 number const const id = 7;
2 number let let pendingTasks = 5;
3 boolean const const isBookedForThursday = true;
4 null let let reviewer = null;
5 number const const MAX_WEEKLY_HOURS = 40;
6 number let let hoursSpent = 3.5;

Case 4 deserves a comment: we use null because we know there is no reviewer assigned, and let because there will be one later. Case 5 goes in UPPER_SNAKE_CASE because it is a global configuration constant.

Exercise 2

Line Output Explanation
A 12 8 Numbers are primitives: assigning copies the value, so they stay independent
B 2 Arrays are copied by reference: copy and tags are the same list
C 'object' A historical bug from 1995 that was never fixed, for compatibility reasons
D 'number' NaN is of type number: it represents an invalid numeric result
E false 0.1 + 0.2 gives 0.30000000000000004 because of the IEEE 754 binary representation
F 'Review the invoices' Strings are immutable: toUpperCase() returns a new one, which is discarded here
G false reviewer is undefined, and undefined === null is false (different types)

Exercise 3

'use strict';

// --- Task data ----------------------------------------------------
const id = 4;
const title = 'Set up the autumn exhibition';
const assignee = 'Lucía';
const priority = 'medium';
let status = 'pending';                    // let: it will change over time
const tags = ['setup', 'event'];
const estimatedHours = 7.5;
const dueDate = '2026-11-05';

// --- Derived values -----------------------------------------------
const isLongTask = estimatedHours > 8;     // false
const uppercaseTitle = title.toUpperCase();

// --- Output --------------------------------------------------------
console.log(`[${id}] ${title}`);
console.log(`Assignee: ${assignee} · Priority: ${priority} · Status: ${status}`);
console.log(`Long task? ${isLongTask} (${estimatedHours} h, due ${dueDate})`);
console.log(`Tags (${tags.length}): ${tags.join(', ')}`);
console.log(`In uppercase: ${uppercaseTitle}`);
console.log(`Original untouched: ${title}`);
console.log(`Type of estimatedHours: ${typeof estimatedHours}`);
console.log(`Type of dueDate: ${typeof dueDate}`);

Output:

[4] Set up the autumn exhibition
Assignee: Lucía · Priority: medium · Status: pending
Long task? false (7.5 h, due 2026-11-05)
Tags (2): setup, event
In uppercase: SET UP THE AUTUMN EXHIBITION
Original untouched: Set up the autumn exhibition
Type of estimatedHours: number
Type of dueDate: string

Notice the last line: dueDate is a string, not a date type. It is a deliberate decision for the project and we will keep it throughout the course.

Conclusion

You now know how to store information. You declare variables with const by default and let when the value changes, and you understand why var belongs to the past (function scope, allowed redeclaration and misleading hoisting). You know about dynamic typing and the typeof operator, with its two famous quirks (typeof null and typeof [] both return 'object'). You have a command of the primitives: string with its template literals and ${} interpolation, number with NaN, Infinity and floating-point precision, boolean, the distinction between undefined and null, and the existence of symbol and bigint. And you have understood the difference between copying by value (primitives) and copying by reference (objects and arrays), which explains why const does not freeze an array.

Above all, you have modeled a complete Nómada Tasks task for the first time, choosing the right type for every field.

Now that you have data, the natural next step is to operate on it. In the next lesson, Basic Operators, you will learn to add up hours, calculate progress percentages, combine logical conditions and use modern operators such as ?? and ?.. With them you will work out the real workload of Marta, Iván and Lucía.

JavaScript Course: From Beginner to Advanced

Module 1: Introduction to JavaScript

Module 2: Control Structures

Module 3: Functions

Module 4: Objects and Arrays

Module 5: Advanced Objects and Functions

Module 6: The Document Object Model (DOM)

Module 7: Browser APIs and Advanced Topics

Module 8: Testing and Debugging

Module 9: Performance and Optimization

Module 10: JavaScript Frameworks and Libraries

Module 11: Final Project

© Copyright 2026. All rights reserved