JavaScript Exponentiation Operator Explained
This article explores how JavaScript evaluates the exponentiation
operator (**), introduced in ECMAScript 2016 (ES7). You
will learn its core syntax, associativity rules, type coercion
behaviors, differences from Math.pow(), and common edge
cases such as handling negative numbers and BigInt
values.
Syntax and Basic Evaluation
The exponentiation operator (**) raises the first
operand (the base) to the power of the second operand (the
exponent).
console.log(2 ** 3); // 8
console.log(5 ** 2); // 25
console.log(4 ** 0.5); // 2 (square root)The operation produces the same mathematical result as \(base^{exponent}\).
Right-Associativity
Unlike most arithmetic operators in JavaScript that evaluate from left to right, the exponentiation operator is right-associative. When multiple exponentiation operators appear in sequence, JavaScript groups and evaluates them from right to left.
console.log(2 ** 3 ** 2); // 512
// Evaluated as: 2 ** (3 ** 2) -> 2 ** 9 = 512
// NOT: (2 ** 3) ** 2 -> 8 ** 2 = 64Unary Operator Ambiguity and Syntax Rules
To prevent ambiguity regarding operator precedence, JavaScript does
not allow a unary operator (+, -,
~, !, typeof, void,
delete) immediately before the base without
parentheses.
// SyntaxError: Unary operator used immediately before exponentiation expression
// -2 ** 2;
// Correct usage:
-(2 ** 2); // -4
(-2) ** 2; // 4Type Coercion and BigInt Support
The exponentiation operator automatically coerces non-numeric primitives to numbers, following standard JavaScript numeric conversion rules:
console.log("3" ** "2"); // 9
console.log(true ** 3); // 1
console.log(null ** 2); // 0
console.log(undefined ** 2); // NaNBigInt Values
The ** operator works with BigInt
primitives, provided both operands are BigInt types. Mixed
operations between BigInt and standard numbers throw a
TypeError.
console.log(2n ** 3n); // 8n
// Negative exponents with BigInt throw a RangeError
// 2n ** -1n; // RangeError: Cannot mix BigInt and other types, use explicit conversionsDifferences Between
** and Math.pow()
While x ** y and Math.pow(x, y) generally
produce the same output, there are two primary differences:
- BigInt Support:
Math.pow()converts all inputs to standard floating-point numbers, whereas**supportsBigInt. - Unary Negation Precedence:
Math.pow(-2, 2)accepts negative values directly as parameters, whereas-2 ** 2requires parentheses(-2) ** 2to avoid syntax errors.
Exponentiation Assignment
Operator (**=)
JavaScript also provides an assignment shorthand, **=,
which calculates the exponentiation and assigns the result back to the
variable:
let value = 3;
value **= 3; // Equivalent to: value = value ** 3
console.log(value); // 27