Basics

Variables and constants

Constants and variables in JavaScript are loosely typed. Expressions (phrases) are evaluated to produce a value, while statements (sentences) are executed to make something happen. Each statement ends with a semicolon. A variable can be created without let or const keywords. In such case, a global variable is created that can be a source of bugs. Use the directive to initiate strict mode to prevent this behavior.

"use strict";

// Constants
const myName = "Roman Akchurin";

// Variables
let myCity = "Moscow";

// Print to console
console.log(myCity);

Numbers

Integers can be expressed in base-10 as well as hexadecimal, octal, or binary representation. Floating-point literals are represented in decimal point format or using exponential notation. Underscores can be used to break long literals for readability.

// Numbers
const decimal = 3.14;
const aDecimal = 0.123_456_789;
const anotherDecimal = 6.02e23;
const yetAnotherDecimal = 1.4738223e-32;
const integer = 1_000_000;
const hexadecimal = 0x89_ab_cd_ef;
const binary = 0b0001_1101_0111;
const octal = 0o277;

BigInt can represent an arbitrarily large integer.

const bigInteger = 1_000_000_000_000_000n;
const bigBinary = 0b0111_1111n;
const bigOctal = 0o7777n;
const bigHexadecimal = 0xab_cd_efn;

// Converting regular numbers or strings to BigInt
const manyZeros = "1" + "0".repeat(100);
const reallyBigNumber = BigInt(manyZeros);

You can perform basic arithmetic with BigInt, however they cannot be mixed with regular numbers.

// Arithmetic with BigInt
1000n + 2000n;
3000n - 2000n;
2000n * 3000n;
3000n / 997n; // => 3n: Division drops the remainder and rounds down
3000n % 997n; // => 9n
2n ** 131071n - 1n; // A Mersenne prime with 39457 decimal digits

As in most other modern programming languages, floating-point representations are not exact in JavaScript.

let pointOne = 0.3 - 0.2;
let anotherPointOne = 0.2 - 0.1;

pointOne === anotherPointOne; // False
pointOne === 0.1; // False
anotherPointOne === 0.1; // True

Math functions

JavaScript has a wide range of built-in math functions.

// Math functions and constants
Math.pow(2, 53);
Math.round(0.6);
Math.ceil(0.6);
Math.floor(0.6);
Math.abs(-5);
Math.max(1, 2, 3);
Math.min(4, 5, 6);
Math.random();
Math.PI;
Math.E;
Math.sqrt(3);
Math.pow(3, 1 / 3);
Math.sin(0);
Math.log(10);
Math.log(100) / Math.LN10;
Math.log(512) / Math.LN2;
Math.exp(3);
Math.cbrt(27); // Cube root
Math.hypot(3, 4); // Square root of sum of squares of all arguments
Math.log10(100);
Math.log2(1024);
Math.log1p(0.01); // Natural log of (1+x)
Math.expm1(0.01); // Math.exp(x) - 1; the inverse of Math.log1p()
Math.sign(-1); // -1, 0, or 1 for <, ==, or > 0
Math.imul(2, 3); // Optimized multiplication of 32-bit integer
Math.clz32(0xf); // Number of leading zero bits in a 32-bit integer
Math.trunc(3.9); // Convert to integer by truncating fractional part
Math.fround(3.4); // Round to nearest 32-bit float number
Math.sinh(1); // Hyperbolic sine. Also Math.cosh(), Math.tanh()
Math.asinh(2); // Hyperbolic arcsine. Also Math.acosh(), Math.atanh()

// Number methods and properties
Number.parseInt("3.14");
Number.parseFloat(".99");
Number.isNaN(NaN);
Number.isFinite(Infinity);
Number.isInteger(3.13);
Number.isSafeInteger(2 ** 53); // Is integer in range -2**53...2**53
Number.MIN_SAFE_INTEGER; // => -(2**53 - 1)
Number.MAX_SAFE_INTEGER; // => 2**53 - 1
Number.EPSILON; // => 2**-52: smallest difference between numbers
Number.NEGATIVE_INFINITY;
Number.POSITIVE_INFINITY;
Number.NaN;
Number.MIN_VALUE;
Number.MAX_VALUE;

Strings

Strings are denoted by a matching pair of single quotes, double quotes, or backticks. String interpolation is possible with backtick notation. Generic escape sequences can represent any character in a string by providing its Unicode character code.

'two\nlines';

"one\
long\
line";

const line_count = 2;
`the newline character at the end of this line
is included in this ${line_count}-line string`;

"\xa9"; // Unicode character © encoded by two hexadecimal digits nn
"\u263A"; // Unicode character ☺ encoded by four hexadecimal digits nnnn
"\u{1F60A}"; // Unicode character 😊 encoded by codepoint n,
// where n is one to six hexadecimal digits between 0 and 10FFFF

String operations

There is a wide range of methods that perform operations on strings in JavaScript. Strings are immutable in JavaScript, therefore string methods always return new strings.

let s = "Hello, " + "world";
s.length; // => 12

// Obtaining portions of string
s.substring(1, 4); // => "ell"
s.slice(1, 4); // => "ell"
s.slice(-3); // => "rld"
s.split(", "); // => ["Hello", "world"]

// Searching a string
s.indexOf("l"); // => 2: position of the first letter l
s.indexOf("l", 3); // => 3: position of fist "l" at or after 3
s.indexOf("zz"); // => -1: s does not include the substring "zz"
s.lastIndexOf("l"); // => 10: position of last letter l

// Boolean searching functions
s.startsWith("Hell"); // => true: the string starts with these
s.endsWith("!"); // => false: s does not end with that
s.includes("or"); // => true: s includes substring "or"

// Creating modified versions of a string
s.replace("llo", "ya"); // => "Heya, world"
s.toLowerCase(); // => "hello, world"
s.toUpperCase(); // => "HELLO, WORLD"
s.normalize(); // Unicode NFC normalization
s.normalize("NFD"); // NFD normalization. Also "NFCK", "NFKD"

// Inspecting individual 16-bit characters of a string
s.charAt(0); // => "H": the first character
s.charAt(s.length - 1); // => "d": the last character
s.charCodeAt(0); // => 72: 16-bit number at the specified position
s.codePointAt(0); // => 72: work for codepoints > 16 bits

// String padding
"x".padStart(3); // => "  x": add spaces on the left to a length of 3
"x".padEnd(3); // => "x  ": add spaces on the right to a length of 3
"x".padStart(3, "*"); // => "**x": add starts on the left to a length of 3
"x".padEnd(3, "-"); // => "x--": add dashes on the right to a length of 3

// String trimming
" test ".trim(); // => "test": remove spaces at start and end
" test ".trimStart(); // => "test ": remove spaces on left. Also trimLeft()
" test ".trimEnd(); // => " test": remove spaces at right. Also trimRight()

// Other string methods
s.concat("!"); // => "Hello world!"
"<>".repeat(5); // => "<><><><><>": concatenate n copies
s[0]; // => "H"
s[s.length - 1]; // => "d"

You don't need parenthesis to invoke a function on template literals.

`\n`.length; // => 1: the string has a single newline character
String.raw`\n`.length; // => 2: a backslash character and the letter n

Regular expressions

Text between a pair of forward slashes makes a regular expression. Letters after the second slash modify the expression.

/^HTML/; // Match the letters H T M L at the start of a string
/[1-9][0-9]*/; // Match a nonzero digit, followed by any # of digits
/\bjavascript\b/i; // Match "javascript" as a word, case-insensitive

const text = "testing: 1, 2, 3"; // Sample text
const pattern = /\d+/g; // Matches all instances of one or more digits
pattern.test(text); // => true: a match exists
text.search(pattern); // => 9: position of first match
text.match(pattern); // ["1", "2", "3"]: array of all matches
text.replace(pattern, "#"); // => "testing: #, #, #"
text.split(/\D+/); // => ["", "1", "2", "3"]: split on nondigits

Boolean values

Boolean values true and false are generally the result of comparison operators in JavaScript. However, values in control structures like if/else statement are converted to boolean values as well. Only the following values are converted to false.

false;
undefined; // System-level, unexpected, or error-like absence of value
null; // Program-level, normal, or expected absence of value
0;
-0;
NaN;
"";

Global object

Global object in JavaScript defines all global identifiers (constants, functions, constructors, and other global objects) that become available when the program starts. In node, the global object has a property global that refers to the global object itself. In web browsers, the same is done with window property. In general, globalThis refers to the global object in any environment.

Primitive types vs. reference types

Number, boolean, string, null and undefined are immutable primitive types. They are equal if they hold the same value. In contrast, object (array is object) is a mutable reference type. Two objects are equal if they refer to the same object.

Type conversions

JavaScript is flexible in converting types to what is expected. However, explicit type conversion can help avoid bugs.

Number("3"); // => 3
+"3"; // => 3
"3" - 0; // => 3
String(false); // => "false"
false + ""; // => "false"
Boolean([]); // => true
!![]; // => true

Number to string conversion can be done with toString() method or more specialized toFixed(), toExponential(), or toPrecision() methods.

const myNumber = 17;
const myBinary = "0b" + myNumber.toString(2); // => "0b10001"
const myOctal = "0o" + myNumber.toString(8); // => "0o21"
const myHexadecimal = "0x" + myNumber.toString(16); // => "0x11"

const anotherNumber = 123456.789;
anotherNumber.toFixed(0); // => "123457"
anotherNumber.toFixed(2); // => "123456.79"
anotherNumber.toFixed(5); // => "123456.78900"
anotherNumber.toExponential(1); // => "1.2e+5"
anotherNumber.toExponential(3); // => "1.235e+5"
anotherNumber.toPrecision(4); // => "1.235e+5"
anotherNumber.toPrecision(7); // => "123456.8"
anotherNumber.toPrecision(10); // => "123456.7890"

String to number conversion can be performed with parseInt() or parseFloat() functions.

parseInt("3 blind mice"); // 3
parseFloat(" 3.14 meters"); // 3.14
parseInt("-12.34"); // -12
parseInt("0xFF"); // 255
parseInt("0xff"); // 255
parseInt("-0xFF"); // -255
parseFloat(".1"); // 0.1
parseInt("0.1"); // 0
parseInt(".1"); // NaN
parseFloat("$72.47"); // NaN

// Optional argument to specify the base
parseInt("11", 2); // 3: (1*2 + 1)
parseInt("ff", 16); // 255: (15*16 + 15)
parseInt("zz", 36); // 1295: (35*36 + 35)
parseInt("077", 8); // 63: (7*8 + 7)
parseInt("077", 10); // 77: (7*10 + 7)

Destructuring

Destructuring is a form of compound declaration in JavaScript. It allows you to initialize variables and constants from objects more easily.

let [x, y] = [1, 2]; // Same as let x=1, y=2
[x, y] = [y, x]; // Swap the values of the two variables

// Copy Math object functions into variables
const { sin, cos, tan } = Math;

// Destructuring array of objects
let points = [
  { x: 1, y: 2 },
  { x: 3, y: 4 },
];
let [{ x: x1, y: y1 }, { x: x2, y: y2 }] = points;

Arrays

Arrays are initialized with square brackets. Undefined elements can be included in an array by omitting a value between commas. A single trailing comma is allowed and does not create an undefined element.

[]; // Empty array
[1,2]; // 2-element array
[1,,,,5]; // Sparse array

Objects

Object initializer is similar to that of arrays, but with curly braces instead. Object properties are access by dot-notation or by using square brackets. Optional chaining allows accessing optional properties without throwing a type error if the property is null or undefined. Optional chaining implements short-circuiting by skipping further evaluation when an invalid property has been accessed.

{}; // Empty object
const q = { x: 1.2, y: -0.5 }; // Object with 2 properties
const rectangle = {
  upperLeft: { x: 2, y: 2 },
  lowerRight: { x: 4, y: 5 }
} // Object with nested objects

rectangle.upperLeft.x; // => 2
q["y"]; // => -0.5
q.z?.r; // => undefined
rectangle.upperRight?.["x"]; // => undefined

Functions

Function definition consists of the keyword function with parameters names in parentheses and a block of code in curly braces. Conditional function invocation allows to skip function invocation with short-circuiting) if the identifier evaluates to null or undefined.

let square = function(x) { return x * x; };
function anotherSquare(x) { return x**2; };
let yetAnotherSquare = x => x * x; // Arrow function

let foo;
foo?.(); // Conditional invocation
q.foo?.(); // Conditional invocation with property access