Computer Programming 1 (JavaScript) • Problem Solving & Mini-Projects

Building Text Analyzer — I can build a text analyzer that computes word frequencies using objects.

Learn to harness JavaScript objects to count, store, and rank every word in a text.

A JavaScript data file with code brackets and a laptop.
Inside this lesson 10 sections 5 questions 7 figures

SECTION 1

Historical Context & Motivation

Counting how often words appear in a document is one of the oldest problems in computing. Long before modern search engines, scholars and code-breakers needed fast, reliable ways to tally words. The field of text analysis — sometimes called computational linguistics — grew out of that need, eventually powering everything from spam filters to autocomplete suggestions on your phone.

1940s • Frequency Analysis in Cryptography

During World War II, letter and word frequency counts became essential tools for breaking enemy ciphers. Analysts tallied character occurrences by hand to find patterns.

1960s • Concordance Programs

Early mainframe computers ran concordance programs that indexed every word in a text along with its position, enabling researchers to study literary works at scale.

1995 • JavaScript Is Born

Brendan Eich created JavaScript in 10 days at Netscape. Its built-in object type made key-value storage — the backbone of word frequency counting — available right in the browser.

2010s • Big Data & NLP

Natural Language Processing (NLP) tools like Google's BERT rely on word frequency statistics as a foundation. The humble word count remains central to modern AI.

The core question this lesson addresses is straightforward: given a block of text, how do we write a program that breaks it into individual words and counts how many times each word appears? JavaScript objects provide an elegant answer because they naturally map unique keys (words) to values (counts).

SECTION 2

Core Principles & Definitions

Before writing any code, you need to understand four foundational ideas that make a text analyzer work. Each one builds on the previous, creating a clear pipeline from raw text to a finished frequency report.

1

Tokenization

Tokenization is the process of splitting a string into individual units called tokens. In our case, each token is a word. JavaScript's .split(" ") method is the simplest way to split on spaces.
2

Normalization

Normalization ensures words like "The" and "the" are treated as the same word. You convert everything to lowercase with .toLowerCase() and strip punctuation so "hello!" matches "hello".
3

Accumulation with Objects

A JavaScript object stores key-value pairs. Each unique word becomes a key, and the value is its count. If the key already exists, you increment the count; if not, you set it to 1.
4

Iteration & Reporting

After accumulating counts, you iterate over the object to display or sort results. Methods like Object.keys() and Object.entries() help you extract and organize the data.
✦

KEY TAKEAWAY

Think of a JavaScript object as a tally sheet. Imagine you are sorting a bag of colored marbles: each time you pull out a red marble, you add a tick mark next to "red" on your sheet. If a color isn't on the sheet yet, you write it down and put the first tick. A JavaScript object works the same way — each word is a color, and each value is the tick-mark count.

SECTION 3

Visual Explanation — The Text-to-Frequency Pipeline

The diagram below traces how a short sentence moves through each stage of the text analyzer pipeline. Follow the arrows from left to right to see raw text transform into a frequency object.

Text Analyzer PipelineRAW TEXT"The cat sat on""the mat."NORMALIZE"the cat sat on""the mat"TOKENIZE["the","cat","sat","on","the","mat"]ACCUMULATE{ the: 2, cat: 1, sat: 1, on: 1, mat: 1 }Accumulation Detail — Looping Through Tokens"the""cat""sat""on""the""mat"key new → 1key new → 1key new → 1key new → 1exists → 2key new → 1FINAL FREQUENCY OBJECT{ the: 2, cat: 1, sat: 1, on: 1, mat: 1 }
The pipeline flows from raw text through normalization and tokenization into the accumulation stage. Notice how "the" appears twice in the token list but results in a single key with a count of 2 in the final object.

Notice the critical moment highlighted in amber in the accumulation detail row: when the loop encounters "the" for the second time, it does not create a new key. Instead, it finds the existing key and increments its value from 1 to 2. This check-then-update pattern is the heart of frequency counting and the reason objects are so well-suited for this task.

SECTION 4

How It Works — The Code Mechanics

Let's translate the visual pipeline into actual JavaScript. There are three key code patterns you need to master: splitting a string into an array, checking whether a property exists on an object, and incrementing a numeric value.

Pattern 1 — String to Array

TOKENIZATION

letwords=text.toLowerCase().replace(/[a−z\s]/g,"").split("");let words = text.toLowerCase().replace(/[^a-z\s]/g, "").split(" ");

.toLowerCase() normalizes case. .replace(/[^a-z\s]/g, "") strips non-letter, non-space characters (punctuation). .split(" ") breaks the string at every space, returning an array of word strings.

Pattern 2 — Check & Update

ACCUMULATION LOGIC

if(freq[word]===undefined)freq[word]=1;elsefreq[word]=freq[word]+1;if (freq[word] === undefined) { freq[word] = 1; } else { freq[word] = freq[word] + 1; }

freq[word] uses bracket notation to look up the current word as a key. If it is undefined, the word hasn't been seen yet, so we initialize it to 1. Otherwise we add 1 to the existing count.

Pattern 3 — Shorthand Increment

CONCISE VERSION

freq[word]=(freq[word]∣∣0)+1;freq[word] = (freq[word] || 0) + 1;

The expression (freq[word] || 0) returns the current count if it exists, or 0 if the key is new. Adding 1 then gives the correct new count in a single line.

⚠

Why Bracket Notation?

You must use freq[word] (bracket notation), not freq.word (dot notation). Dot notation would literally look for a property called "word", whereas bracket notation evaluates the variable word to get the actual string value like "the" or "cat".

SECTION 5

Detailed Breakdown — The Complete Text Analyzer

Now let's combine all three patterns into a complete, working function. The diagram below shows the full code alongside a visual trace of its execution with sample input.

Complete Text Analyzer FunctionCODEfunction analyzeText(text) {let cleaned = text.toLowerCase().replace(/[^a-z\s]/g, "");let words = cleaned.split(" ");let freq = {};for (let i = 0;i < words.length; i++) {let w = words[i];if (w === "") continue;freq[w] = (freq[w] || 0) + 1;}return freq;}EXECUTION TRACEInput: "To be or not to be!"cleaned → "to be or not to be"words → ["to","be","or","not","to","be"]Loop iterations:i=0 w="to" freq={to:1}i=1 w="be" freq={to:1, be:1}i=2 w="or" freq={to:1, be:1, or:1}i=3 w="not" freq={..., not:1}i=4 w="to" freq={..., to:2} ★i=5 w="be" freq={..., be:2} ★★ = key already existed, incrementedREPORTING — Finding the Most Frequent Wordlet result = analyzeText("To be or not to be!");let entries = Object.entries(result);// [["to",2],["be",2],["or",1],["not",1]]entries.sort(function(a, b) {return b[1] - a[1]; // descending by count});console.log(entries[0]); // ["to", 2]
The left panel shows the complete analyzeText function. The right panel traces execution with the input "To be or not to be!" — iterations 4 and 5 (marked with ★) demonstrate the increment path. The bottom panel shows how to sort results by frequency using Object.entries() and .sort().

There are a few subtle details worth noting. The if (w === "") continue; line handles the edge case of extra spaces in the input, which would produce empty strings in the array. The regex pattern /[^a-z\s]/g matches any character that is not a lowercase letter or whitespace and replaces it with nothing, effectively stripping all punctuation. The sorting step uses a custom comparator that subtracts counts in reverse order (b[1] - a[1]) to arrange words from most to least frequent.

SECTION 6

Worked Example — Analyzing a Paragraph

Let's walk through a longer example step by step. Suppose we want to analyze the sentence: "I think, therefore I am. I think."

Analyzing "I think, therefore I am. I think."

  1. 1

    Step 1 — Normalize the Text

    Convert to lowercase: "i think, therefore i am. i think.". Then strip punctuation with the regex: "i think therefore i am i think".
    "i think therefore i am i think"
  2. 2

    Step 2 — Tokenize into an Array

    Split on spaces to produce an array of seven elements: ["i", "think", "therefore", "i", "am", "i", "think"]. Note that "i" appears three times and "think" appears twice.
    Array length = 7
  3. 3

    Step 3 — Initialize an Empty Object

    Create let freq = {};. This empty object will hold our word-count pairs.
    freq = {}
  4. 4

    Step 4 — Loop and Accumulate

    Iterate through the array. For each word, apply freq[w] = (freq[w] || 0) + 1. After i=0: {i:1}. After i=1: {i:1, think:1}. After i=2: {i:1, think:1, therefore:1}. After i=3: {i:2, think:1, therefore:1}. After i=4: {i:2, think:1, therefore:1, am:1}. After i=5: {i:3, ...}. After i=6: {i:3, think:2, ...}.
    { i: 3, think: 2, therefore: 1, am: 1 }
  5. 5

    Step 5 — Report the Results

    The most frequent word is "i" with a count of 3. The total number of unique words is 4 (the number of keys in the object). You can find this with Object.keys(freq).length.
    Most frequent: "i" (3 occurrences); Unique words: 4

SECTION 7

Strengths & Limitations of the Object Approach

Using a plain JavaScript object for word frequencies is simple and effective, but it isn't the only option. Understanding the trade-offs helps you choose the right tool as your projects grow more complex.

FeaturePlain Object {}Map()
Syntax simplicityVery simple — curly braces, bracket notationSlightly more verbose — uses .set() and .get()
Key typesStrings and symbols onlyAny data type (numbers, objects, etc.)
Order of keysNot guaranteed (though usually insertion order)Guaranteed insertion order
Built-in sizeNeed Object.keys(obj).lengthUse .size property directly
Best for word frequency?Great choice for learning and small-medium textsBetter for very large datasets or non-string keys

Comparison of object-based vs. Map-based frequency counting

✦

KEY TAKEAWAY

A plain JavaScript object is like a pocket notebook — lightweight, easy to open, and perfect for jotting down quick tallies. A Map is more like a full spreadsheet application — more powerful and precise, but heavier than you need for a straightforward word-count task. Start with the notebook; upgrade when you outgrow it.

SECTION 8

Connection to Advanced Concepts

The text analyzer you've built is a stepping stone toward powerful computer science ideas. The concept of mapping keys to values is one of the most fundamental data-structure patterns, and it reappears in many advanced contexts.

This LessonAdvanced Version
Counting word frequencies with an objectHash maps / hash tables in data structures courses
Stripping punctuation with a simple regexFull Natural Language Processing (NLP) tokenizers that handle contractions, hyphens, and Unicode
Sorting by count to find the most frequent wordTF-IDF (Term Frequency–Inverse Document Frequency) for ranking word importance across many documents
Analyzing a single stringProcessing entire file systems or web-scraped content using Node.js streams

From this lesson to advanced applications

If this topic sparks your interest, consider exploring sentiment analysis next — it uses word frequency data to determine whether a piece of text expresses a positive, negative, or neutral emotion. You already have the foundation; the next step is connecting frequency counts to a list of "positive" and "negative" words and computing a score.

SECTION 9

Practice Problems

Question 1: CONCEPTUAL

Explain why using an object (instead of a simple array) is a good choice for storing word frequencies. What role do the object's keys and values play?
Show answer
An object lets you use each unique word as a key and its count as the corresponding value. This means you can look up any word's count instantly using bracket notation, such as freq["hello"]. With a plain array, you would have no natural way to associate a word with its count without a second parallel array or a more complicated search. Objects give you direct, name-based access — which is exactly what frequency counting requires.

Question 2: BASIC CALCULATION

Trace through the following code and write the exact value of freq after the loop finishes: let words = ["red", "blue", "red", "red", "blue", "green"]; let freq = {}; for (let i = 0; i < words.length; i++) { freq[words[i]] = (freq[words[i]] || 0) + 1; }
Show answer
After the loop, freq equals { red: 3, blue: 2, green: 1 }. "red" appears at indices 0, 2, and 3 (count 3). "blue" appears at indices 1 and 4 (count 2). "green" appears only at index 5 (count 1). Each iteration either creates a new key set to 1 or increments an existing key by 1.

Question 3: INTERMEDIATE

Write a function called mostFrequentWord(text) that takes a string, computes word frequencies, and returns the word with the highest count. If two words tie, returning either one is acceptable. Describe your approach before writing the code.
Show answer
First, normalize and tokenize the text as before. Then loop through the frequency object to find the key with the maximum value. One approach: initialize let maxWord = ""; let maxCount = 0;. Use a for...in loop over the object. Inside the loop, compare freq[key] > maxCount; if true, update maxWord = key and maxCount = freq[key]. After the loop, return maxWord. This adds only one extra loop beyond the accumulation step, keeping the solution efficient.

Question 4: APPLIED

You are building a simple plagiarism detector for student essays. You decide to compare the frequency objects of two essays. Write a function sharedWords(freqA, freqB) that takes two frequency objects and returns an array of words that appear in both. How could comparing frequencies (not just shared words) help detect copying?
Show answer
Loop through the keys of freqA using for (let word in freqA). For each word, check whether freqB[word] !== undefined; if so, push it to a results array. Beyond just finding shared words, you could compare the actual counts: if two essays use the same uncommon word with very similar frequencies, that's a stronger signal of copying than sharing common words like "the" or "is". You could compute a similarity score by summing the absolute differences in counts for shared words.

Question 5: CRITICAL THINKING

Common English words like "the", "is", and "a" dominate any frequency list. These are called stop words. Design a modification to the analyzeText function that accepts an array of stop words and excludes them from the frequency object. Explain where in the code the check should go and why that placement matters.
Show answer
Add a second parameter: function analyzeText(text, stopWords). Inside the loop, after assigning let w = words[i];, add a check: if (stopWords.includes(w)) continue;. This skips the accumulation step for any stop word. The check must go before the increment line so that stop words never enter the frequency object at all. Placing it after would mean the word has already been counted. For better performance on large stop-word lists, you could convert the stop-words array into a Set and use .has() instead of .includes(), which is faster for large collections.

SUMMARY

Lesson Summary

Summary

In this lesson you built a complete text analyzer by combining three core JavaScript skills. First, you used normalization (.toLowerCase() and .replace()) to clean raw input. Then you performed tokenization with .split(" ") to break text into an array of words. Finally, you applied the accumulation pattern — freq[w] = (freq[w] || 0) + 1 — to build a frequency object where each key is a unique word and each value is its count.

You also learned to sort results using Object.entries() and a custom comparator, compared plain objects with Map for key-value storage, and saw how this project connects to advanced topics like NLP and TF-IDF. The object-based frequency counter is a versatile pattern you can reuse in spam detection, sentiment analysis, and any project that needs to summarize text data.

Varsity Tutors • Computer Programming 1 (JavaScript) • Building Text Analyzer — I can build a text analyzer that computes word frequencies using objects.