completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

Strict mode

Learn how JavaScript strict mode turns silent mistakes into errors, how the "use strict" directive prologue works, and why modules and classes are strict automatically.

By the end, you can
  • 01
    Put the line in the right placeExplain why "use strict" only works at the very top of a script or a function.
  • 02
    Predict strict-mode errorsSay when sloppy mode stays quiet and when strict mode throws a ReferenceError, a TypeError, or a SyntaxError.
  • 03
    Know what is strict alreadyKnow that ES modules and classes are strict without writing "use strict" yourself.

Strict mode in one sentence

Strict mode is a stricter way for JavaScript to run your code. Most code works the same in it. But in a few places, old JavaScript guesses what you meant and keeps going. Strict mode stops there with an error instead. Then you can see the mistake and fix it.

The old, default way is often called sloppy mode. This lesson uses that name.

Ordinary code still worksPop out in the code editor (opens in a new tab)JavaScript
const price = 3;
console.log(price + 1);

Line 1 stores 3 in price. Line 2 adds one and prints 4. Strict mode does not change normal math like this. It only changes a few risky cases. You will meet them below.

Real-life analogyA form that won't send with a missing field

Picture a sign-up form on a website. If you leave a required field empty, the form does not send. It shows a red message instead. Strict mode works the same way for some risky JavaScript. It stops with an error instead of guessing.

In real life: An empty required field stops the form from sending
In JavaScript: Assigning to a name you never declared throws a ReferenceError
In real life: A locked field refuses a change
In JavaScript: A write that can't happen throws a TypeError
In real life: The rules apply to one form
In JavaScript: "use strict" applies to one script or one function
Definition

You turn strict mode on by writing the exact text "use strict"; at the very top of a script or a function. Two kinds of code are strict on their own, with no extra line: ES modules (files that use import and export) and the code inside a class.

In this lesson, a classic script means a normal script that is not a module, like a plain <script> tag. You will compare sloppy mode with strict mode. You will learn exactly where "use strict" has to go. You will also see why modules are already strict.

Where "use strict" must go

STEP THROUGH

"use strict" looks like a string because it is one. But at the top of a script or a function, JavaScript gives some strings a special job. A string with a special job like this is called a directive. It is an instruction to JavaScript, not a value for your program to use.

The strings at the very top, one after another, are called the directive prologue. (A prologue is the opening part of something.) The rules are:

  • Blank lines and comments may come before "use strict".
  • Other plain strings may come before it too.
  • Any other statement ends the prologue. A statement is one complete instruction, like console.log("hi");.
  • After that, "use strict" is just a string. JavaScript reads it and does nothing with it.
Left: a script whose first line is use strict, so strict mode is on. Right: a script whose first line is console.log, then use strict on line 2, which is ignored, so the script stays in sloppy mode.at the topscript.js"use strict";typoTotal = 3;strict mode is onafter another linescript.jsconsole.log("hi");"use strict";ignoredstill sloppy mode
The same line, "use strict";, in two places. On the first line, it turns strict mode on. After another statement, it is too late. JavaScript reads it as a plain string and ignores it.
Make only one function strictPop out in the code editor (opens in a new tab)JavaScript
function saveTeaOrder() {
  "use strict";
  try {
    teaTotal = 3;
  } catch (error) {
    return error.name;
  }
}

console.log(saveTeaOrder());

Line 2 is the first statement inside saveTeaOrder. So it makes only that function strict. Line 4 assigns to teaTotal, but teaTotal was never declared. (Declared means made with let, const, or var.) Strict mode throws a ReferenceError. The catch block catches the error, and line 6 returns its name. Line 10 prints ReferenceError.

One string directive can follow anotherPop out in the code editor (opens in a new tab)JavaScript
"keep this note";
"use strict";
try {
  cartTotal = 3;
} catch (error) {
  console.log(error.name);
}

Line 1 is another plain string. It does not end the prologue, so line 2 still turns strict mode on. Line 4 assigns to cartTotal, which was never declared. That throws, and line 6 prints ReferenceError. Only a statement that is not a plain string ends the prologue.

A comment can come before the directivePop out in the code editor (opens in a new tab)JavaScript
// Comments do not count as statements.
"use strict";
try {
  guestCount = 2;
} catch (error) {
  console.log(error.name);
}

JavaScript skips the comment on line 1. So line 2 is still in the prologue, and strict mode is on. Line 4 assigns to guestCount, which was never declared. The catch block gets a ReferenceError, and line 6 prints ReferenceError. A comment is a note for people, so it never ends the prologue.

Move "use strict" and step through
Step 0 of 3Ready
Your turn: follow the blue line

Choose where "use strict" goes, then step through. The results come from a real JavaScript run.

Running in
  1. script
Next: line 1
try {  typoTotal = 3;  console.log("assignment worked");} catch (error) {  console.log(error.name + ": " + error.message);}
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
Where is "use strict"?

Changing the place starts the step-through again.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

In the first version, line 3 throws right away, so the mistake with typoTotal shows up at once. In the second version, line 1 prints setup first. Now the prologue is over, so line 2 is ignored. Line 3 then quietly makes a new global variable, globalThis.typoTotal. (A global is a variable that every part of the program can see.) The words are the same. Only their place is different.

Strict mode for one function

"use strict" can also be the first line inside a function. Then only that function is strict. Older websites used this to move to strict mode one function at a time. New code usually uses modules instead.

Strict or sloppy?
  • "use strict"; as the first line of a classic script
  • console.log("hi"); before "use strict";
  • A function whose first line is "use strict";
  • An ES module file
  • A classic script with no "use strict"
  • Code inside a class body
Try it yourself
0 of 6 correct

Sort each piece of code: does it run in strict mode or in sloppy mode? Remember: a classic script needs "use strict" at the top. Modules and classes don't.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

One more rule: once code is strict, you can't turn strict mode off inside it. A string like "use sloppy" means nothing special. Placement also matters when a tool pastes several files into one big file. A file's "use strict" may end up below other code. Then it is no longer at the top, so it stops working.

What strict mode changes

INTERACTIVE

Strict mode is not a new language. Most JavaScript works the same in both modes. The changes are in the places where old JavaScript would quietly guess, skip an error, or allow confusing code.

A name you never declared throwsPop out in the code editor (opens in a new tab)JavaScript
"use strict";
try {
  orderTotal = 3;
} catch (error) {
  console.log(error.name);
}

Line 1 turns strict mode on for this script. Line 3 assigns to orderTotal, but orderTotal was never declared. Strict mode throws, and line 5 prints ReferenceError. No new variable is made.

The line orderTotal = 3, with no let, const, or var. Left, in sloppy mode: a new box called orderTotal appears holding 3, a hidden global. Right, in strict mode: a ReferenceError card, and nothing is made.orderTotal = 3;sloppy mode3orderTotala hidden global is madestrict modeReferenceErrornothing is madeyou see the mistake
The same line, orderTotal = 3;, with no let, const, or var. Sloppy mode quietly makes a new global variable. Strict mode makes nothing and throws a ReferenceError, so you see the mistake.

In sloppy mode, the same line makes a new global variable without telling you. So a typo in a name can quietly make a global, and that global can change code far away. That is why strict mode refuses.

A declared name can still changePop out in the code editor (opens in a new tab)JavaScript
"use strict";
let orderTotal = 3;
orderTotal = orderTotal + 1;
console.log(orderTotal);

Strict mode still lets you assign values. Line 2 declares orderTotal. Line 3 changes it, and line 4 prints 4. The problem is only a name that was never declared. Changing a variable you made on purpose is fine.

Run the same mistake in both modes
Sloppy versionPop out in the code editor (opens in a new tab)JavaScript
mistakeCount = 1;console.log("created global: " + ("mistakeCount" in globalThis));
What the browser printedRun either version to see what the browser really prints.

A classic script is in sloppy mode unless "use strict" is on its first line.

Try it yourself

Strict mode catches the typo. It does not make a new global variable. Sloppy mode prints: created global: true. Strict mode gives: ReferenceError: mistakeCount is not defined.

The browser really runs this code, as a classic script, inside a hidden, walled-off page. The lesson only shows a result that came from that page.

A frozen object shows a second change. Object.freeze(obj) locks an object, so its properties can't be changed. Then, if your code tries to change one:

  • In sloppy mode, the change is skipped with no message.
  • In strict mode, the change throws a TypeError.

The step-through below tries the change in strict mode. Then it reads the name again, so you can see that nothing changed.

Step through a write that strict mode refuses
Step 0 of 4Ready
Your turn: follow the blue line

This replays the example step by step. Strict mode reports the failed write, and the frozen profile stays the same.

Running in
  1. script
Next: line 1
const profile = Object.freeze({ name: "Grace" });try {  profile.name = "Asha";} catch (error) {  console.log(error.name);}console.log(profile.name);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Object.freeze only locks the outer objectPop out in the code editor (opens in a new tab)JavaScript
"use strict";
const profile = Object.freeze({
  name: "Asha",
  preferences: { theme: "light" },
});
profile.preferences.theme = "dark";
console.log(profile.preferences.theme);

Object.freeze is shallow: it locks only the object you pass to it. The preferences object inside is a separate object, and it is not locked. So line 6 changes the theme, and line 7 prints dark. To lock the inner objects too, freeze each one of them.

Each row of this table is one risky case. Read across to see what each mode does.

What each mode does in risky cases
When your code does thisSloppy modeStrict mode
Assigns to a name that was never declaredMakes a new global variable.Throws a ReferenceError.
Calls a function with nothing before the dotthis is the global object.this stays undefined.
Writes to something that can't changeSkips the write with no message.Throws a TypeError.
Gives two parameters the same nameAllowed in old-style functions.A SyntaxError before any code runs.
Writes an old octal number like 010Reads it as eight.A SyntaxError. Write 0o10 instead.
Uses a with statementChanges where names are looked up.A SyntaxError.

You don't need to remember every old case today. Remember the pattern instead. Strict mode refuses code that:

  • makes a hidden global variable,
  • hides a write that failed,
  • makes it hard to tell where a name comes from.

A plain function call keeps this undefined

ONE SMALL RULE

Inside a function, this is a special word. It means "the object this function was called on." A plain function call is a call like showUser(), with no object and dot before the name. So what is this then?

  • In sloppy mode, JavaScript fills in the global object. That is the object that holds all the globals. You can reach it as globalThis.
  • In strict mode, JavaScript fills in nothing, so this stays undefined.
Check this in a plain callPop out in the code editor (opens in a new tab)JavaScript
"use strict";
function showUser() {
  console.log(this === undefined);
}

showUser();

Line 1 turns strict mode on. Lines 2 to 4 make a function that checks whether this is undefined. Line 6 calls it with nothing before the dot. So line 3 prints true.

This rule is only for plain calls. In user.showName(), user is before the dot, so this is user. The playground above has a this example too. Run it in both modes to compare.

A call with a dot gives the function its objectPop out in the code editor (opens in a new tab)JavaScript
"use strict";
const user = {
  name: "Asha",
  showName() {
    console.log(this.name);
  },
};

user.showName();

Line 2 makes a user object with the name Asha. A function stored in an object, like showName, is called a method. Line 9 calls the method through user. So inside showName, this is the user object, and line 5 prints Asha. Strict mode keeps this useful rule. It only removes the surprise for plain calls.

Left: user.showUser(). The showUser function card is in the user cart, so this is user. Right: showUser(). The same function card is alone in a box called showUser, so in strict mode this is undefined.user.showUser()showUser()userthis = usershowUser()showUser()showUserthis = undefined
The same function, called two ways. With user before the dot, this is user. With nothing before the dot, strict mode leaves this as undefined.

Each row is one way to call a strict function, and the value this gets.

What this is for each kind of call
How you call itValue of thisWhy
showUser()undefinedNothing is before the dot, so no object is given.
user.showUser()useruser is before the dot, so the function gets user.

Mistakes strict mode refuses before running

Some strict rules are about how code is written. JavaScript checks these before it runs a single line. If one is broken, nothing runs. You get a SyntaxError: an error that means "this code is not written in a valid way."

Four things strict mode refusesPop out in the code editor (opens in a new tab)JavaScript
"use strict";function total(a, a) {  return a;} console.log(010); delete total; with ({ total: 1 }) {  console.log(total);}
  • Two parameters with the same name, like (a, a) on line 2. A parameter is a name for a value passed into a function. With two as, one hides the other.
  • Old octal numbers, like 010 on line 6. Octal means counting in eights, so 010 meant eight. But most readers think it means ten. To write octal, use 0o10.
  • Deleting a variable, like delete total on line 8. delete removes a property from an object. It was never a way to remove a variable.
  • The with statement, on line 10. It changes where JavaScript looks for names, so strict mode bans it. A later lesson, Sloppy mode in depth, shows why old code used it.
Write octal numbers with 0oPop out in the code editor (opens in a new tab)JavaScript
console.log(0o10);

The 0o at the start means "this is an octal number." This line prints 8. In everyday code, you will almost always use normal numbers. The point is that the new way to write octal is clear.

Delete a property, not a variablePop out in the code editor (opens in a new tab)JavaScript
"use strict";
const cart = { coupon: "SAVE" };
delete cart.coupon;
console.log("coupon" in cart);

Strict mode bans delete total. But you can still remove a property from an object. Line 3 removes the coupon property from cart. Line 4 checks whether coupon is still in cart, and prints false.

These errors come before anything runs

When a strict script has a SyntaxError, its own try/catch can't catch it. The script never starts running, so its catch never runs either. Your editor, the browser console, or your test tool shows the error instead.

Strict by default in modules and classes

SORT

In 2015, a JavaScript update called ES2015 made two features strict on their own: modules and classes.

  • An ES module is a JavaScript file that can use import and export to share code with other files.
  • A class body is the code inside a class's braces { }: its fields and methods.

Neither one needs "use strict".

Three windows. A classic script tag is sloppy by default and needs use strict. A script with type module is strict already. A class body is strict already.script<script>sloppy by defaultneeds "use strict"moduletype="module"strict alreadyno extra line neededclassclass Cart {}strict alreadyno extra line needed
A classic script starts in sloppy mode, so it needs "use strict"; at the top. A module and the code inside a class are strict already. They need no extra line.
Modules and classes are already strictJavaScript
// ES module file, or <script type="module">const moduleThis = this; class StrictCounter {  count = 0;  bump() {    return this.count + 1;  }} console.log(moduleThis === undefined);console.log(new StrictCounter().bump());

This example only works as a module. The lesson's code runner runs classic scripts, and there the top-level this is different. So this example is here for reading only. The lesson's tests run the same code as a real module.

In a module, this at the top level (outside any function) is undefined, not the global object. Inside a class body, methods and fields follow strict rules too. This is one reason modern code uses modules: they start in the safer mode.

So the module example prints true, then 1. The first console.log checks the top-level this. The second one calls the class method. The next example prints ReferenceError, because a class body is strict even inside a classic script.

A class method is strict without "use strict"Pop out in the code editor (opens in a new tab)JavaScript
class Profile {  rename() {    try {      missingName = "Asha";    } catch (error) {      return error.name;    }  }}console.log(new Profile().rename());

Line 4 assigns to missingName, which was never declared. This whole example has no "use strict" line. But the method is inside a class, so it is strict anyway. The catch block catches the ReferenceError, and line 6 returns its name. Line 10 prints ReferenceError.

Do you need to add a directive?
  • <script src="app.js"></script>
  • <script type="module" src="app.js"></script>
  • class Counter { bump() { return this.count + 1; } }
  • <script>total = 1;</script>
Try it yourself
0 of 4 correct

Decide for each piece of code: does it need "use strict"; to be strict, or is it strict already?

Choose a category for every card. You can change an answer at any time; Reset clears them all.
Classic scripts still exist

A plain <script> tag without type="module" is a classic script. Classic scripts are where "use strict" still matters most.

Where you will use this

You won't type "use strict" every day. But you will use strict mode every day without typing it.

A framework is a ready-made toolkit for building apps. A bundler is a tool that joins your files into a few files for the browser. Frameworks, bundlers, and many editors make or expect module code. Module code is strict, so strict mode is the normal starting point today.

Strict mode does not check how you spell property names. On a normal object, you can still add a property with a misspelled name. The next small example shows this.

Strict mode does not catch every property typoPop out in the code editor (opens in a new tab)JavaScript
"use strict";
const user = {};
user.nmae = "Asha";
console.log(user.name);

Line 1 turns strict mode on. Line 3 adds a new property, nmae, to user. That is allowed, because user is a normal object that can still get new properties. Line 4 reads name, which was never set, so it prints undefined. Strict mode catches a write that fails. It does not catch a spelling mistake that JavaScript allows.

A real bug strict mode catchesPop out in the code editor (opens in a new tab)JavaScript
"use strict"; function saveProfile(profile) {  profile.naem = "Ada"; // typo: meant profile.name  return profile.name;} const profile = Object.freeze({ name: "Grace" });console.log(saveProfile(profile));

Here the profile object is frozen, so JavaScript can't add naem to it. The write on line 4 fails. Because the script is strict, the failed write throws a TypeError. Freezing makes the write fail. Strict mode makes the failure visible.

Fix an old classic scriptPop out in the code editor (opens in a new tab)JavaScript
"use strict";
function saveOrder() {
  const orderTotal = 3;
  console.log(orderTotal);
}

saveOrder();

Maybe you have an old classic script that you can't turn into a module yet. Put "use strict"; on the first line, and declare the variable you need. Here line 3 declares orderTotal. Line 7 calls saveOrder, so line 4 prints 3. For new files, use a module script instead. It is strict already, and it can import other files.

  • Use modules when you can. They are strict on their own and work well with modern tools.
  • When you write an old-style classic script, put "use strict"; on the first line.
  • When you read older code, notice sloppy-mode habits. Don't copy them into new files.
  • When strict mode throws, treat the error as help. It found a bug early.

Common misconceptions

“Strict mode makes every program faster.”

Strict mode is not a speed switch. Use it because it catches mistakes.

“A comment before "use strict" breaks it.”

Comments and blank lines before it are fine. Only a statement that is not a plain string, like console.log("hi");, ends the prologue.

“I can turn strict mode off later.”

You can't. Once code is strict, a later string can't make that code sloppy again.

“Modules need "use strict" at the top.”

They don't. Modules are strict on their own. Adding the line does no harm, but it also does nothing.

“Strict mode fixes all bugs.”

It only catches some old, risky cases. Mistakes in your logic, like adding the wrong number, still need tests.

“Strict mode catches every misspelled property.”

A normal object accepts a new property, even a misspelled one like user.nmae. Tests, or a tool that checks your code such as TypeScript, can catch that kind of typo.

The same text can mean two different things. Read each row to see why.

The same string, in different places
What you seeWhere it isWhat it does
"use strict";At the top of a script or function, before other statements.It is a directive. It turns strict mode on.
"use strict";After console.log(...), let total = 0, or another statement.It is just a string. JavaScript ignores it.
A commentBefore the directive.JavaScript skips it. It does not end the prologue.

Practice: spot strict mode

5 EXERCISES
Exercise 1 · Warm-upPredict the caught error

Read the code. Which error name does the catch block print?

Starter codePop out in the code editor (opens in a new tab)JavaScript
"use strict";
try {
  usernmae = "Ada";
  console.log("saved");
} catch (error) {
  console.log(error.name);
}

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeAdd strict mode correctly

    Make this classic script strict. Which line must come first?

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    let total = 0;
    total = total + 1;
    console.log(total);

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeFind why "use strict" did nothing

      This code makes a global instead of throwing. Type the short reason.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      console.log("start");
      "use strict";
      missingName = 1;
      console.log(globalThis.missingName);

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeTurn a silent write into an error you can see

        Which error name shows that the write to the frozen object was caught?

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        "use strict";
        const account = Object.freeze({ role: "reader" });
        try {
          account.role = "admin";
        } catch (error) {
          console.log(error.name);
        }

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeReal-world choice: classic script or module?

          You are fixing a checkout page. A typo there can make a hidden global. Answer two things:

          • For new code, would you use a module or a classic script?
          • For an old classic script you can't change to a module yet, what goes on the first line, and what would you fix in the function?
          Starter codePop out in the code editor (opens in a new tab)JavaScript
          function saveOrder() {
            orderTtoal = 3;
          }

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: check your understanding

            8 QUESTIONS

            Pick the best answer. The lesson's tests run every code question, so the answers match what JavaScript really prints.

            Lesson quiz · 8 questionsScore: first tries count
            1. Question 1 of 8What is the main job of strict mode?

              Choose an answer to see the explanation.

            2. Question 2 of 8Where must "use strict"; go to make a classic script strict?

              Choose an answer to see the explanation.

            3. Question 3 of 8What does this strict program print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              "use strict";
              try {
                total = 1;
              } catch (error) {
                console.log(error.name);
              }

              Choose an answer to see the explanation.

            4. Question 4 of 8This strict program checks this in a plain call. What does it print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              "use strict";
              function showThis() {
                console.log(this === undefined);
              }
              showThis();

              Choose an answer to see the explanation.

            5. Question 5 of 8What does this strict script print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              "use strict";
              const user = {};
              user.nmae = "Asha";
              console.log(user.name);

              Choose an answer to see the explanation.

            6. Question 6 of 8Which code is strict without writing "use strict"?

              Choose an answer to see the explanation.

            7. Question 7 of 8A tool pastes several files into one big file. Why can that stop "use strict" from working?

              Choose an answer to see the explanation.

            8. Question 8 of 8Which old feature does strict mode ban because it makes it hard to tell where a name comes from?

              Choose an answer to see the explanation.

            Key takeaways

            • "use strict" only works at the very top of a script or a function, in the directive prologue.
            • Strict mode turns some silent mistakes into errors you can see. Two big ones: assigning to a name you never declared, and writing to something that can't change.
            • It also refuses some confusing code before it runs: two parameters with the same name, old octal numbers like 010, deleting a variable, and with.
            • Modules and class bodies are strict on their own. A classic script needs "use strict" to be strict.
            • Once code is strict, you can't turn strict mode off inside it.

            Remember the one-liner.
            Strict mode is JavaScript's safer mode: it stops old, silent mistakes so you can fix them early.

            Coming next: Talking to the user.

            CompleteFrontend Clear concepts. Working examples.