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.
- 01Put the line in the right placeExplain why
"use strict"only works at the very top of a script or a function. - 02Predict strict-mode errorsSay when sloppy mode stays quiet and when strict mode throws a
ReferenceError, aTypeError, or aSyntaxError. - 03Know what is strict alreadyKnow that ES modules and classes are strict without writing
"use strict"yourself.
Watch the video lecture
Full course on YouTube (opens in a new tab) ↗- Lecture 7What "use strict" doesWatch on YouTube (opens in a new tab) ↗
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.
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.
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
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.
"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.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.
"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.
// 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.
Choose where "use strict" goes, then step through. The results come from a real JavaScript run.
script
try { typoTotal = 3; console.log("assignment worked");} catch (error) { console.log(error.name + ": " + error.message);}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.
"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.
"use strict";as the first line of a classic scriptconsole.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
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.
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
INTERACTIVEStrict 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.
"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.
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.
"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.
mistakeCount = 1;console.log("created global: " + ("mistakeCount" in globalThis));A classic script is in sloppy mode unless "use strict" is on its first line.
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.
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.
This replays the example step by step. Strict mode reports the failed write, and the frozen profile stays the same.
script
const profile = Object.freeze({ name: "Grace" });try { profile.name = "Asha";} catch (error) { console.log(error.name);}console.log(profile.name);"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.
| When your code does this | Sloppy mode | Strict mode |
|---|---|---|
| Assigns to a name that was never declared | Makes a new global variable. | Throws a ReferenceError. |
| Calls a function with nothing before the dot | this is the global object. | this stays undefined. |
| Writes to something that can't change | Skips the write with no message. | Throws a TypeError. |
| Gives two parameters the same name | Allowed in old-style functions. | A SyntaxError before any code runs. |
Writes an old octal number like 010 | Reads it as eight. | A SyntaxError. Write 0o10 instead. |
Uses a with statement | Changes 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 RULEInside 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
thisstaysundefined.
"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.
"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.
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.
| How you call it | Value of this | Why |
|---|---|---|
showUser() | undefined | Nothing is before the dot, so no object is given. |
user.showUser() | user | user 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."
"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 twoas, one hides the other. - Old octal numbers, like
010on line 6. Octal means counting in eights, so010meant eight. But most readers think it means ten. To write octal, use0o10. - Deleting a variable, like
delete totalon line 8.deleteremoves a property from an object. It was never a way to remove a variable. - The
withstatement, 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.
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.
"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.
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
SORTIn 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
importandexportto 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".
"use strict"; at the top. A module and the code inside a class are strict already. They need no extra line.// 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.
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.
<script src="app.js"></script><script type="module" src="app.js"></script>class Counter { bump() { return this.count + 1; } }<script>total = 1;</script>
Decide for each piece of code: does it need "use strict"; to be strict, or is it strict already?
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.
"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.
"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.
"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.
| What you see | Where it is | What 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 comment | Before the directive. | JavaScript skips it. It does not end the prologue. |
Practice: spot strict mode
5 EXERCISESRead the code. Which error name does the catch block print?
"use strict";
try {
usernmae = "Ada";
console.log("saved");
} catch (error) {
console.log(error.name);
}The program prints ReferenceError. Strict mode won't make a new global for the misspelled name usernmae. It throws instead, and the catch block prints the error's name.
Make this classic script strict. Which line must come first?
let total = 0;
total = total + 1;
console.log(total);"use strict";
let total = 0;
total = total + 1;
console.log(total);Put "use strict"; on the first line. Then the rest of the classic script runs in strict mode. It still prints 1.
This code makes a global instead of throwing. Type the short reason.
console.log("start");
"use strict";
missingName = 1;
console.log(globalThis.missingName);"use strict" comes too late. console.log("start") is a statement before it, so the string on line 2 is ignored. The script stays in sloppy mode, so line 3 makes a global.
Which error name shows that the write to the frozen object was caught?
"use strict";
const account = Object.freeze({ role: "reader" });
try {
account.role = "admin";
} catch (error) {
console.log(error.name);
}The catch block prints TypeError. The object is frozen, so account.role = "admin" can't work. Strict mode reports the failed write as a TypeError.
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?
function saveOrder() {
orderTtoal = 3;
}"use strict";
function saveOrder() {
const orderTotal = 3;
console.log(orderTotal);
}
saveOrder();For a new app, use a module script. It is strict on its own, and it can use import. For an old classic script, put "use strict"; on the first line. Then declare orderTotal with const and spell it correctly.
Quiz: check your understanding
8 QUESTIONSPick the best answer. The lesson's tests run every code question, so the answers match what JavaScript really prints.
Question 1 of 8What is the main job of strict mode?
Choose an answer to see the explanation.
Question 2 of 8Where must
"use strict";go to make a classic script strict?Choose an answer to see the explanation.
Question 3 of 8What does this strict program print?
Read the code, then predict"use strict"; try { total = 1; } catch (error) { console.log(error.name); }Choose an answer to see the explanation.
Question 4 of 8This strict program checks
thisin a plain call. What does it print?Read the code, then predict"use strict"; function showThis() { console.log(this === undefined); } showThis();Choose an answer to see the explanation.
Question 5 of 8What does this strict script print?
Read the code, then predict"use strict"; const user = {}; user.nmae = "Asha"; console.log(user.name);Choose an answer to see the explanation.
Question 6 of 8Which code is strict without writing
"use strict"?Choose an answer to see the explanation.
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.
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, andwith. - 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.