Hello World

  • The type and language attributes are not required.

  • The benefit of a separate file is that the browser will download it and store it in its cache. Other pages that reference the same script will take it from the cache instead of downloading it, so the file is actually downloaded only once.

  • If src is set, the script content is ignored.

    <script src="file.js">
      alert(1); // the content is ignored, because src is set
    </script>

Semicolons

In most cases, a newline implies a semicolon. But “in most cases” does not mean “always”!

There are cases when a newline does not mean a semicolon. For example:

alert(3 +
1
+ 2);

Now let’s remove the semicolon after the alert:

alert("Hello")
 
[1, 2].forEach(alert);

JavaScript does not assume a semicolon before square brackets [...]. So, the code in the last example is treated as a single statement.

alert("Hello")[1, 2].forEach(alert);

We recommend putting semicolons between statements even if they are separated by newlines. This rule is widely adopted by the community.

Strict Mode

Modern JavaScript supports “classes” and “modules” – advanced language structures (we’ll surely get to them), that enable use strict automatically. So we don’t need to add the "use strict" directive, if we use them.

So, for now "use strict"; is a welcome guest at the top of your scripts. Later, when your code is all in classes and modules, you may omit it.

Data Types

We can put any type in a variable. For example, a variable can at one moment be a string and then store a number:

// no error
let message = "hello";
message = 123456;

Programming languages that allow such things, such as JavaScript, are called “dynamically typed”, meaning that there exist data types, but variables are not bound to any of them.

Number

Besides regular numbers, there are so-called “special numeric values” which also belong to this data type: Infinity, -Infinity and NaN:

  • Infinity: represents the mathematical Infinity ∞. It is a special value that’s greater than any number.

  • NaN: represents a computational error. NaN is sticky. Any further mathematical operation on NaN returns NaN:

    alert( NaN + 1 ); // NaN
    alert( 3 * NaN ); // NaN
    alert( "not a number" / 2 - 1 ); // NaN

So, if there’s a NaN somewhere in a mathematical expression, it propagates to the whole result (there’s only one exception to that: NaN ** 0 is 1).

BigInt

The “number” type cannot safely represent integer values larger than (253-1) (that’s 9007199254740991), or less than -(253-1) for negatives.

To be really precise, the “number” type can store larger integers (up to 1.7976931348623157 * 10308), but outside of the safe integer range ±(253-1) there’ll be a precision error, because not all digits fit into the fixed 64-bit storage. So an “approximate” value may be stored.

For example, these two numbers (right above the safe range) are the same:

console.log(9007199254740991 + 1); // 9007199254740992
console.log(9007199254740991 + 2); // 9007199254740992

BigInt type was recently added to the language to represent integers of arbitrary length.

A BigInt value is created by appending n to the end of an integer:

// the "n" at the end means it's a BigInt
const bigInt = 1234567890123456789012345678901234567890n;

Null and Undefined

Normally, one uses null to assign an “empty” or “unknown” value to a variable, while undefined is reserved as a default initial value for unassigned things.

Objects and Symbols

All other types are called “primitive” because their values can contain only a single thing (be it a string or a number or whatever). In contrast, objects are used to store collections of data and more complex entities.

Typeof

The result of typeof null is "object". That’s an officially recognized error in typeof, coming from very early days of JavaScript and kept for compatibility.

Functions belong to the object type. But typeof treats them differently, returning "function".

Info

You may also come across another syntax: typeof(x). It’s the same as typeof x.

To put it clear: typeof is an operator, not a function. The parentheses here aren’t a part of typeof. It’s the kind of parentheses used for mathematical grouping.

Alert, Prompt and Confirm

All these methods are modal: they pause script execution and don’t allow the visitor to interact with the rest of the page until the window has been dismissed.

Type Conversion

Numeric Conversion – Occurs in math operations. Can be performed with Number(value).

The conversion follows the rules:

ValueBecomes…
undefinedNaN
null0
true and false1 and 0
stringWhitespaces (includes spaces, tabs \t, newlines \n etc.) from the start and end are removed. If the remaining string is empty, the result is 0. Otherwise, the number is “read” from the string. An error gives NaN.

Examples:

alert( Number("   123   ") ); // 123
alert( Number("123z") );      // NaN (error reading a number at "z")
alert( Number(true) );        // 1
alert( Number(false) );       // 0

Boolean Conversion – Occurs in logical operations. Can be performed with Boolean(value).

Follows the rules:

ValueBecomes…
0, null, undefined, NaN, ""false
any other valuetrue

Space characters are trimmed off string start and end when a string is converted to a number. Here the whole string consists of space characters, such as \t, \n and a “regular” space between them. So, similarly to an empty string, it becomes 0.

Example:

" \t \n" - 2 = -2 // (7)

On the other hand, the equality check == for undefined and null is defined such that, without any conversions, they equal each other and don’t equal anything else. That’s why (2) null == 0 is false in the following example:

alert( null > 0 );  // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true

Operators

Unary operators are higher than corresponding binary ones.

Example:

// both values converted to numbers before the binary plus
alert( +apples + +oranges ); // 5

Increment/decrement

The prefix form returns the new value while the postfix form returns the old value (prior to increment/decrement).

To see the difference, here’s an example:

let counter = 1;
let a = ++counter; // (*)
 
alert(a); // 2

Now, let’s use the postfix form:

let counter = 1;
let a = counter++; // (*) changed ++counter to counter++
 
alert(a); // 1

To summarize:

If the result of increment/decrement is not used, there is no difference in which form to use:

let counter = 0;
counter++;
++counter;
alert( counter ); // 2, the lines above did the same

If we’d like to increase a value and immediately use the result of the operator, we need the prefix form:

let counter = 0;
alert( ++counter ); // 1

If we’d like to increment a value but use its previous value, we need the postfix form:

let counter = 0;
alert( counter++ ); // 0

The operators ++/-- can be used inside expressions as well. Their precedence is higher than most other arithmetical operations.

OR and AND

Precedence of AND && is higher than OR ||

The precedence of AND && operator is higher than OR ||.

So the code a && b || c && d is essentially the same as if the && expressions were in parentheses: (a && b) || (c && d).

Nullish

The important difference between || and ?? is that:

  • || returns the first truthy value.
  • ?? returns the first defined value.

For example, consider this:

let height = 0;
 
alert(height || 100); // 100
alert(height ?? 100); // 0

The precedence of the ?? operator is the same as ||. That means that, just like ||, the nullish coalescing operator ?? is evaluated before = and ?, but after most other operations, such as +, *.

Resources