Master JavaScript

What JavaScript is, and how to run it

7 / 266
Contents

Contents

Master JavaScript

0 of 266 complete

10 min read

Comments, names, and the three dialects

How to write a note, what a name is allowed to contain, and why the same file means different things depending on how it is loaded.

Some of what you write in a file is not for the computer. A comment is text the engine skips entirely, there for whoever reads the code next, which is usually you in three months.

Try CodeJavaScript

Put // in front of the console.log line and run it again.

Two forms, and only two. // ignores the rest of the line. /* ignores everything up to the next */, across as many lines as you like. There is no third form, and # is not a comment.

The hashbang

There is one exception to # not being a comment. If the very first two characters of a file are #!, that whole first line is ignored. It is called a hashbang, and it lets a Unix system know which program should run the file.

#!/usr/bin/env node
console.log("hello");
Saved as greet, made executable with chmod +x greet, then run as ./greet.

It has to be the first line: a blank line or a comment above it is a syntax error. Engines had allowed this for years before it was written into the specification in ES2023, which is a good example of the standard catching up with practice rather than leading it.

What a name may be made of

A name you invent, for a variable or a function, is called an identifier. The rules are looser than most people expect.

Try CodeJavaScript

Rename café to something in another alphabet and run it again. Then try starting a name with a digit and read the error.

An identifier may start with a letter from any alphabet in Unicode, or with $ or _. After the first character it may also contain digits. It may not start with a digit, it may not contain a space or a hyphen, and case matters: total and Total are two different names.

It also may not be a reserved word, one of the names the grammar has already claimed: let, const, var, function, return, if, else, for, while, class, new, this, typeof, delete, import, export, null, true, false and a few dozen more.

Three dialects

The same characters in the same file can be read three different ways, and which one you get is decided outside the file, by how it was loaded. The three are called sloppy mode, strict mode and module. Here is the difference that matters most.

Try CodeJavaScript

The name undeclaredThing was never declared. Change the number 1 to a piece of text and see what the answer becomes.

Assigning to a name that was never declared did not fail. It created a global variable, visible to the entire program, from inside a function. A single typo in a variable name silently makes a new one, and the original keeps its old value.

That is sloppy mode, the original behaviour of the language, kept forever because the web is full of pages that depend on it. Now the same code with one line added.

Try CodeJavaScript

It stops with ReferenceError: totalCount is not defined. Add let in front of totalCount = 1; and run it again.

The line "use strict"; is a directive: a plain piece of text that the language treats as an instruction when it is the very first statement of a file or of a function body. Anywhere else it is an ordinary string that does nothing at all.

Strict mode was added in ES5 in 2009. It does not add features. It turns a list of silent mistakes into errors, and removes a few constructions that made the language hard to reason about. Once switched on for a scope it cannot be switched off again inside it.

Written in the codeSloppyStrictModule
Assign to a name never declaredCreates a globalReferenceErrorReferenceError
Write to a frozen propertyIgnored in silenceTypeErrorTypeError
Two parameters with the same nameAllowedSyntaxErrorSyntaxError
An old octal number such as 0755AllowedSyntaxErrorSyntaxError
this inside a plain function callglobalThisundefinedundefined
import and exportSyntaxErrorSyntaxErrorThe whole point
delete applied to a variable nameAllowed, does nothingSyntaxErrorSyntaxError
Top-level declarationsShared with everything else loadedShared with everything else loadedPrivate to the file unless exported
What each dialect does with the same code.

The this row is there for completeness; this has a lesson of its own in the section on objects, and the difference matters there rather than here.

How you end up in each one

  • A .js file run by Node.js in a package with no "type" setting, holding no import or export, is a CommonJS script, and it is sloppy unless the file starts with "use strict";.
  • The same file with an import or an export somewhere in it is loaded as a module by recent versions of Node.js, and is therefore strict. Node.js tries it as a script first, fails, notices the module syntax, and reads it again as a module, printing a warning while it does so.
  • A .mjs file, or any .js file in a package whose package.json says "type": "module", is a module, and modules are strict with no way to opt out.
  • In a browser, <script> is sloppy and <script type="module"> is a module.
  • The body of a class is always strict, wherever it appears. Classes come later in the course.
You add "use strict"; as the tenth line of a file. What changes?

Nothing. A directive only counts when it is the first statement of a file or of a function body. On line ten it is an ordinary expression statement: a piece of text, evaluated and discarded. There is no warning, which is why the mistake survives.

Check yourself

A function's first line is "use strict";, and its second is count = 1;, where count was never declared anywhere. What happens, and what would have happened without that first line?

All lessons in Master JavaScript