Assignment operators

An assignment operator assigns a value to its left operand based on the value of its right operand. The simple assignment operator is equal (=), which assigns the value of its right operand to its left operand. That is, x = f() is an assignment expression that assigns the value of f() to x.

Assigning to properties

If an expression evaluates to an object, then the left-hand side of an assignment expression may make assignments to properties of that expression. For example:

const obj = {};

obj.x = 3;
console.log(obj.x); // Prints 3.
console.log(obj); // Prints { x: 3 }.

const key = "y";
obj[key] = 5;
console.log(obj[key]); // Prints 5.
console.log(obj); // Prints { x: 3, y: 5 }.

For more information about objects, read Working with Objects.

If an expression does not evaluate to an object, then assignments to properties of that expression do not assign:

const val = 0;
val.x = 3;

console.log(val.x); // Prints undefined.
console.log(val); // Prints 0.

In strict mode, the code above throws, because one cannot assign properties to primitives.

It is an error to assign values to unmodifiable properties or to properties of an expression without properties (null or undefined).

Destructuring

For more complex assignments, the destructuring assignment syntax is a JavaScript expression that makes it possible to extract data from arrays or objects using a syntax that mirrors the construction of array and object literals.

JSCopy to Clipboard

const foo = ["one", "two", "three"];

// without destructuring
const one = foo[0];
const two = foo[1];
const three = foo[2];

// with destructuring
const [one, two, three] = foo;

Evaluation and nesting

In general, assignments are used within a variable declaration (i.e., with const, let, or var) or as standalone statements).

// Declares a variable x and initializes it to the result of f().
// The result of the x = f() assignment expression is discarded.
let x = f();

x = g(); // Reassigns the variable x to the result of g().

However, like other expressions, assignment expressions like x = f() evaluate into a result value. Although this result value is usually not used, it can then be used by another expression.

Chaining assignments or nesting assignments in other expressions can result in surprising behavior. For this reason, some JavaScript style guides discourage chaining or nesting assignments). Nevertheless, assignment chaining and nesting may occur sometimes, so it is important to be able to understand how they work.

By chaining or nesting an assignment expression, its result can itself be assigned to another variable. It can be logged, it can be put inside an array literal or function call, and so on.

let x;
const y = (x = f()); // Or equivalently: const y = x = f();
console.log(y); // Logs the return value of the assignment x = f().

console.log(x = f()); // Logs the return value directly.

// An assignment expression can be nested in any place
// where expressions are generally allowed,
// such as array literals' elements or as function calls' arguments.
console.log([0, x = f(), 0]);
console.log(f(0, x = f(), 0));

The evaluation result matches the expression to the right of the = sign in the "Meaning" column of the table above. That means that x = f() evaluates into whatever f()'s result is, x += f() evaluates into the resulting sum x + f(), x **= f() evaluates into the resulting power x ** y, and so on.

In the case of logical assignments, x &&= f(), x ||= f(), and x ??= f(), the return value is that of the logical operation without the assignment, so x && f(), x || f(), and x ?? f(), respectively.

When chaining these expressions without parentheses or other grouping operators like array literals, the assignment expressions are grouped right to left (they are right-associative), but they are evaluated left to right.

Note that, for all assignment operators other than = itself, the resulting values are always based on the operands' values before the operation.

For example, assume that the following functions f and g and the variables x and y have been declared:

function f() {
  console.log("F!");
  return 2;
}
function g() {
  console.log("G!");
  return 3;
}
let x, y;

Consider these three examples:

y = x = f();
y = [f(), x = g()];
x[f()] = g();

Evaluation example 1

y = x = f() is equivalent to y = (x = f()), because the assignment operator = is right-associative. However, it evaluates from left to right:

  1. The assignment expression y = x = f() starts to evaluate.

    1. The y on this assignment's left-hand side evaluates into a reference to the variable named y.

    2. The assignment expression x = f() starts to evaluate.

      1. The x on this assignment's left-hand side evaluates into a reference to the variable named x.

      2. The function call f() prints "F!" to the console and then evaluates to the number 2.

      3. That 2 result from f() is assigned to x.

    3. The assignment expression x = f() has now finished evaluating; its result is the new value of x, which is 2.

    4. That 2 result in turn is also assigned to y.

  2. The assignment expression y = x = f() has now finished evaluating; its result is the new value of y – which happens to be 2. x and y are assigned to 2, and the console has printed "F!".

Evaluation example 2

y = [ f(), x = g() ] also evaluates from left to right:

  1. The assignment expression y = [ f(), x = g() ] starts to evaluate.

    1. The y on this assignment's left-hand evaluates into a reference to the variable named y.

    2. The inner array literal [ f(), x = g() ] starts to evaluate.

      1. The function call f() prints "F!" to the console and then evaluates to the number 2.

      2. The assignment expression x = g() starts to evaluate.

        1. The x on this assignment's left-hand side evaluates into a reference to the variable named x.

        2. The function call g() prints "G!" to the console and then evaluates to the number 3.

        3. That 3 result from g() is assigned to x.

      3. The assignment expression x = g() has now finished evaluating; its result is the new value of x, which is 3. That 3 result becomes the next element in the inner array literal (after the 2 from the f()).

    3. The inner array literal [ f(), x = g() ] has now finished evaluating; its result is an array with two values: [ 2, 3 ].

    4. That [ 2, 3 ] array is now assigned to y.

  2. The assignment expression y = [ f(), x = g() ] has now finished evaluating; its result is the new value of y – which happens to be [ 2, 3 ]. x is now assigned to 3, y is now assigned to [ 2, 3 ], and the console has printed "F!" then "G!".

Evaluation example 3

x[f()] = g() also evaluates from left to right. (This example assumes that x is already assigned to some object. For more information about objects, read Working with Objects.)

  1. The assignment expression x[f()] = g() starts to evaluate.

    1. The x[f()] property access on this assignment's left-hand starts to evaluate.

      1. The x in this property access evaluates into a reference to the variable named x.

      2. Then the function call f() prints "F!" to the console and then evaluates to the number 2.

    2. The x[f()] property access on this assignment has now finished evaluating; its result is a variable property reference: x[2].

    3. Then the function call g() prints "G!" to the console and then evaluates to the number 3.

    4. That 3 is now assigned to x[2]. (This step will succeed only if x is assigned to an object.)

  2. The assignment expression x[f()] = g() has now finished evaluating; its result is the new value of x[2] – which happens to be 3. x[2] is now assigned to 3, and the console has printed "F!" then "G!".

Avoid assignment chains

Chaining assignments or nesting assignments in other expressions can result in surprising behavior. For this reason, chaining assignments in the same statement is discouraged).

In particular, putting a variable chain in a const, let, or var statement often does not work. Only the outermost/leftmost variable would get declared; other variables within the assignment chain are not declared by the const/let/var statement. For example:

JSCopy to Clipboard

const z = y = x = f();

This statement seemingly declares the variables x, y, and z. However, it only actually declares the variable z. y and x are either invalid references to nonexistent variables (in strict mode) or, worse, would implicitly create global variables for x and y in sloppy mode.

Last updated