The JavaScript Guide shows you how to use JavaScript and gives an overview of the language. If you need exhaustive information about a language feature, have a look at the JavaScript reference. This Guide is divided into the following chapters.
Introduction
Overview: Introduction
- About this guide
- About JavaScript
- JavaScript and Java
- ECMAScript
- Tools
- Hello World
Grammar and types
Overview: Grammar and types
- Basic syntax & comments
- Declarations
- Variable scope
- Variable hoisting
- Data structures and types
- Literals
Control flow and error handling
Overview: Control flow and error handling
if...else
switch
try
/catch
/throw
- Error objects
Loops and iteration
Overview: Loops and iteration
for
while
do...while
continue
break
for...in
for...of
Functions
Overview: Functions
- Defining functions
- Calling functions
- Function scope
- Closures
- Arguments & parameters
- Arrow functions
Expressions and operators
Overview: Expressions and operators
- Assignment & Comparisons
- Arithmetic operators
- Bitwise & logical operators
- Conditional [ternary] operator
Numbers and dates
Overview: Numbers and dates
- Number literals
Number
objectMath
objectDate
object
Text formatting
Overview: Text formatting
- String literals
String
object- Template literals
- Internationalization
- Regular Expressions
Indexed collections
Overview: Indexed collections
- Arrays
- Typed arrays
Keyed collections
Overview: Keyed collections
Map
WeakMap
Set
WeakSet
Working with objects
Overview: Working with objects
- Objects and properties
- Creating objects
- Defining methods
- Getter and setter
Using classes
Overview: Using classes
- Declaring a class
- Various class features
- Extends and inheritance
- Why classes?
Promises
Overview: Promises
- Guarantees
- Chaining
- Error propagation
- Composition
- Timing
Iterators and generators
Overview: Iterators and generators
- Iterators
- Iterables
- Generators
Meta programming
Overview: Meta programming
Proxy
- Handlers and traps
- Revocable Proxy
Reflect
JavaScript modules
Overview: JavaScript modules
- Exporting
- Importing
- Default exports
- Renaming features
- Aggregating modules
- Dynamic module loading
- Next »
JavaScript is a multi-paradigm, dynamic language with types and operators, standard built-in objects, and methods. Its syntax is based on the Java and C languages — many structures from those languages apply to JavaScript as well. JavaScript supports object-oriented programming with object prototypes and classes. It
also supports functional programming since functions are first-class that can be easily created via expressions and passed around like any other object. This page serves as a quick overview of various JavaScript language features, written for readers with background in other languages, such as C or Java. Let's start off by looking at the building blocks of any language: the types. JavaScript programs manipulate values, and those values all belong to a type. JavaScript offers seven primitive types: Everything else is known as an
Object. Common object types include: Functions aren't special data structures in JavaScript — they are just a special type of object
that can be called. JavaScript has two built-in numeric types: Number and BigInt. The Number type is a IEEE 754 64-bit double-precision floating point
value, which means integers can be safely represented between -[253 − 1] and 253 − 1 without loss of precision, and floating point numbers can be stored all the way up to
1.79 × 10308. Within numbers, JavaScript does not distinguish between floating point numbers and integers.Data types
true
and false
— usually used for conditional logic.Function
Array
Date
RegExp
Error
Numbers
console.log[3 / 2]; // 1.5, not 1
So an apparent integer is in fact implicitly a float. Because of IEEE 754 encoding, sometimes floating point arithmetic can be imprecise.
console.log[0.1 + 0.2]; // 0.30000000000000004
For operations that expect integers, such as bitwise operations, the number will be converted to a 32-bit integer.
Number literals can also have prefixes to indicate the base [binary, octal, decimal, or hexadecimal], or an exponent suffix.
console.log[0b111110111]; // 503
console.log[0o767]; // 503
console.log[0x1f7]; // 503
console.log[5.03e2]; // 503
The BigInt type is an
arbitrary length integer. Its behavior is similar to C's integer types [e.g. division truncates to zero], except it can grow indefinitely. BigInts are specified with a number literal and an n
suffix.
console.log[-3n / 2n]; // -1n
The standard arithmetic operators are supported, including addition, subtraction, remainder arithmetic, etc. BigInts and numbers cannot be mixed in arithmetic operations.
The Math
object provides standard mathematical functions and constants.
Math.sin[3.5];
const circumference = 2 * Math.PI * r;
There are three ways to convert a string to a number:
parseInt[]
, which parses the string for an integer.parseFloat[]
, which parses the string for a floating-point number.- The
Number[]
function, which parses a string as if it's a number literal and supports many different number representations.
You can also use the
unary plus +
as a shorthand for Number[]
.
Number values also include NaN
[short for "Not a Number"] and Infinity
. Many "invalid
math" operations will return NaN
— for example, if attempting to parse a non-numeric string, or using Math.log[]
on a negative value. Division by zero produces Infinity
[positive or negative].
NaN
is contagious: if you provide it as an operand to any mathematical operation, the result will also be NaN
. NaN
is the only value in JavaScript that's not equal
to itself [per IEEE 754 specification].
Strings
Strings in JavaScript are sequences of Unicode characters. This should be welcome news to anyone who has had to deal with internationalization. More accurately, they are UTF-16 encoded.
console.log["Hello, world"];
console.log["你好,世界!"]; // Nearly all Unicode characters can be written literally in string literals
Strings can be written with either single or double quotes — JavaScript does not have the distinction between characters and strings. If you want to represent a single character, you just use a string consisting of that single character.
console.log["Hello"[1] === "e"]; // true
To find the length of a string [in code units], access its length
property.
Strings have utility methods to manipulate the string and access information about the string. Because all primitives are immutable by design, these methods return new strings.
The +
operator is overloaded for strings: when one of the operands is a string, it performs string concatenation instead of number addition. A special template literal syntax allows you to write strings with
embedded expressions more succinctly. Unlike Python's f-strings or C#'s interpolated strings, template literals use backticks [not single or double quotes].
const age = 25;
console.log["I am " + age + " years old."]; // String concatenation
console.log[`I am ${age} years old.`]; // Template literal
Other types
JavaScript distinguishes between
null
, which indicates a deliberate non-value [and is only accessible through the null
keyword], and undefined
, which indicates absence of value. There are many ways to obtain undefined
:
- A
return
statement with no value [return;
] implicitly returnsundefined
. - Accessing a nonexistent object property [
obj.iDontExist
] returnsundefined
. - A variable declaration without initialization [
let x;
] will implicitly initialize the variable toundefined
.
JavaScript has a Boolean type, with possible values true
and false
— both of which are keywords. Any value can be converted to a boolean according to the following rules:
false
,0
, empty strings [""
],NaN
,null
, andundefined
all becomefalse
.- All other values become
true
.
You can perform this conversion explicitly using the
Boolean[]
function:
Boolean[""]; // false
Boolean[234]; // true
However, this is rarely necessary, as JavaScript will silently perform this conversion when it expects a boolean, such as in an if
statement [see Control structures]. For this reason, we sometimes
speak of "truthy" and "falsy", meaning values that become true
and false
, respectively, when used in boolean contexts.
Boolean operations such as &&
[logical and], ||
[logical or], and !
[logical not] are supported; see
Operators.
The Symbol type is often used to create unique identifiers. Every symbol created with the Symbol[]
function is guaranteed to be unique. In addition, there are registered symbols, which are shared constants, and well-known symbols, which are utilized
by the language as "protocols" for certain operations. You can read more about them in the symbol reference.
Variables
Variables in JavaScript are
declared using one of three keywords: let
, const
, or var
.
let
allows you to declare block-level variables. The declared variable is available
from the block it is enclosed in.
let a;
let name = "Simon";
// myLetVariable is *not* visible out here
for [let myLetVariable = 0; myLetVariable {
let sum = 0;
for [const item of args] {
sum += item;
}
return sum / args.length;
};
// You can omit the `return` when simply returning an expression
const sum = [a, b, c] => a + b + c;
Arrow functions are not semantically equivalent to function expressions — for more information, see its reference page.
There's another way that anonymous functions can be useful: it can be simultaneously declared and invoked in a single expression, called an Immediately invoked function expression [IIFE]:
[function [] {
// …
}][];
For use-cases of IIFEs, you can read emulating private methods with closures.
Recursive functions
JavaScript allows you to call functions recursively. This is particularly useful for dealing with tree structures, such as those found in the browser DOM.
function countChars[elm] {
if [elm.nodeType === 3] {
// TEXT_NODE
return elm.nodeValue.length;
}
let count = 0;
for [let i = 0, child; [child = elm.childNodes[i]]; i++] {
count += countChars[child];
}
return count;
}
Function expressions can be named as well, which allows them to be recursive.
const charsInBody = [function counter[elm] {
if [elm.nodeType === 3] {
// TEXT_NODE
return elm.nodeValue.length;
}
let count = 0;
for [let i = 0, child; [child = elm.childNodes[i]]; i++] {
count += counter[child];
}
return count;
}][document.body];
The name provided to a function expression as above is only available to the function's own scope. This allows more optimizations to be done by the engine and results in more readable code. The name also shows up in the debugger and some stack traces, which can save you time when debugging.
If you are used to functional programming, beware of the performance implications of recursion in JavaScript. Although the language specification specifies tail-call optimization, only JavaScriptCore [used by Safari] has implemented it, due to the difficulty of recovering stack traces and debuggability. For deep recursion, consider using iteration instead to avoid stack overflow.
Functions are first-class objects
JavaScript functions are first-class objects. This means that they can be assigned to variables, passed as arguments to other functions, and returned from other functions. In addition, JavaScript supports closures out-of-the-box without explicit capturing, allowing you to conveniently apply functional programming styles.
// Function returning function
const add = [x] => [y] => x + y;
// Function accepting function
const babies = ["dog", "cat", "hen"].map[[name] => `baby ${name}`];
Note that JavaScript functions are themselves objects — like everything else in JavaScript — and you can add or change properties on them just like we've seen earlier in the Objects section.
Inner functions
JavaScript function declarations are allowed inside other functions. An important detail of nested functions in JavaScript is that they can access variables in their parent function's scope:
function parentFunc[] {
const a = 1;
function nestedFunc[] {
const b = 4; // parentFunc can't use this
return a + b;
}
return nestedFunc[]; // 5
}
This provides a great deal of utility in writing more maintainable code. If a called function relies on one or two other functions that are not useful to any other part of your code, you can nest those utility functions inside it. This keeps the number of functions that are in the global scope down.
This is also a great counter to the lure of global variables. When writing complex code, it is often tempting to use global variables to share values between multiple functions, which leads to code that is hard to maintain. Nested functions can share variables in their parent, so you can use that mechanism to couple functions together without polluting your global namespace.
Classes
JavaScript offers the class syntax that's very similar to languages like Java.
class Person {
constructor[name] {
this.name = name;
}
sayHello[] {
return `Hello, I'm ${this.name}!`;
}
}
const p = new Person["John"];
console.log[p.sayHello[]];
JavaScript classes are just functions that must be instantiated with the new
operator. Every time a class is instantiated, it returns an object containing the methods and properties that the class
specified. Classes don't enforce any code organization — for example, you can have functions returning classes, or you can have multiple classes per file. Here's an example of how ad-hoc the creation of a class can be: it's just an expression returned from an arrow function. This pattern is called a mixin.
const withAuthentication = [cls] =>
class extends cls {
authenticate[] {
// …
}
};
class Admin extends withAuthentication[Person] {
// …
}
Static properties are created by prepending static
.
Private properties are created by prepending a hash #
[not private
]. The hash is an integral part of the property name. [Think about #
as _
in Python.] Unlike most other languages, there's absolutely no way to read a private property outside the class body — not even in derived classes.
For a detailed guide on various class features, you can read the guide page.
Asynchronous programming
JavaScript is single-threaded by nature. There's no paralleling; only concurrency. Asynchronous programming is powered by an event loop, which allows a set of tasks to be queued and polled for completion.
There are three idiomatic ways to write asynchronous code in JavaScript:
- Callback-based [such as
setTimeout[]
] Promise
-basedasync
/await
, which is a syntactic sugar for Promises
For example, here's how a file-read operation may look like in JavaScript:
// Callback-based
fs.readFile[filename, [err, content] => {
// This callback is invoked when the file is read, which could be after a while
if [err] {
throw err;
}
console.log[content];
}];
// Code here will be executed while the file is waiting to be read
// Promise-based
fs.readFile[filename]
.then[[content] => {
// What to do when the file is read
console.log[content];
}].catch[[err] => {
throw err;
}];
// Code here will be executed while the file is waiting to be read
// Async/await
async function readFile[filename] {
const content = await fs.readFile[filename];
console.log[content];
}
The core language doesn't specify any asynchronous programming features, but it's crucial when interacting with the external environment — from asking user permissions, to fetching data, to reading files. Keeping the potentially long-running operations async ensures that other processes can still run while this one waits — for example, the browser will not freeze while waiting for the user to click a button to grant permission.
If you have an async value, it's not possible to get its value synchronously. For example, if you have a promise, you can only access the eventual result via the then[]
method. Similarly,
await
can only be used in an async context, which is usually an async function or a module. Promises are never blocking — only the logic depending on the promise's result will be deferred; everything else continues to execute in the meantime. If you are a functional programmer, you may recognize promises as
monads which can be mapped with then[]
[however, they are not proper monads because they auto-flatten; i.e. you can't have a Promise
].
In fact, the single-threaded model has made Node.js a popular choice for server-side programming due to its non-blocking IO, making handling a large number of database or file-system requests very performant. However, CPU-bound [computationally intensive] tasks that's pure JavaScript will still block the main thread. To achieve real paralleling, you may need to use workers.
To learn more about asynchronous programming, you can read about using promises or follow the asynchronous JavaScript tutorial.
Modules
JavaScript also specifies a module system supported by most runtimes. A module is usually a file, identified by it's file path or
URL. You can use the import
and export
statements to exchange data between modules:
import { foo } from "./foo.js";
// Unexported variables are local to the module
const b = 2;
export const a = 1;
Unlike Haskell, Python, Java, etc., JavaScript module resolution is entirely host-defined — it's usually based on URLs or file paths, so relative file paths "just work" and are relative to the current module's path instead of some project root path.
However, the JavaScript language doesn't offer standard library modules — all core functionalities are powered by global variables like Math
and Intl
instead.
This is due to the long history of JavaScript lacking a module system, and the fact that opting into the module system involves some changes to the runtime setup.
Different runtimes may use different module systems. For example, Node.js uses the package manager npm and is mostly file-system based, while Deno and browsers are fully URL-based and modules can be resolved from HTTP URLs.
For more information, see the modules guide page.
Language and runtime
Throughout this page, we've constantly mentioned that certain features are language-level while others are runtime-level.
JavaScript is a general-purpose scripting language. The core language specification focuses on pure computational logic. It doesn't deal with any
input/output — in fact, without extra runtime-level APIs [most notably console.log[]
], a JavaScript program's behavior is entirely unobservable.
A runtime, or a host, is something that feeds data to the JavaScript engine [the interpreter], provides extra global properties, and provides hooks for the engine to interact with the outside world. Module resolution, reading data, printing messages, sending network requests, etc. are all runtime-level operations. Since its inception, JavaScript has been adopted in various environments, such as browsers [which provide APIs like DOM], Node.js [which provides APIs like file system access], etc. JavaScript has been successfully integrated in web [which was its primary purpose], mobile apps, desktop apps, server-side apps, serverless, embedded systems, and more. While you learn about JavaScript core features, it's also important to understand host-provided features in order to put the knowledge to use. For example, you can read about all web platform APIs, which are implemented by browsers, and sometimes non-browsers.
Further exploration
This page offers a very basic insight into how various JavaScript features compare with other languages. If you want to learn more about the language itself and the nuances with each feature, you can read the JavaScript guide and the JavaScript reference.
There are some essential parts of the language that we have omitted due to space and complexity, but you can explore on your own:
- Inheritance and the prototype chain
- Closures
- Regular expressions
- Iteration