Proposal for Conditional Assignment Operators in JavaScript

Introduction:

JavaScript, as a dynamic and high-level language, consistently equips developers with innovative tools that enhance coding efficiency and readability. Among these tools are the Nullish coalescing assignment (??= ), Logical OR assignment (||= ), and Logical AND assignment (&&= ) operators. The ??= operator has revolutionized the way we handle null and undefined values, while the ||= and &&= operators have simplified the assignment of values based on their truthiness. These operators have significantly improved the expressiveness of JavaScript, yet there is still potential for further refinement and expansion of these concepts.

Proposal:

This proposal introduces three new assignment operators: =??, =||, and =&&. These operators aim to enhance the way we assign values to variables based on certain conditions, making the code more concise and readable.

  1. The =?? Operator:

The =?? operator is proposed as a shorthand for a = b ?? a;. This means that a will be assigned the value of b only if b is not null or undefined. If b is null or undefined, a retains its original value. This operator can be particularly useful when we want to update a variable only if a new value exists.

  1. The =|| Operator:

The =|| operator is proposed as a shorthand for a = b || a;. This means that a will be assigned the value of b only if b is truthy. If b is falsy, a retains its original value. This operator can be useful when we want to update a variable only if a new value is truthy.

  1. The =&& Operator:

The =&& operator is proposed as a shorthand for a = b && a;. This means that a will be assigned the value of b only if b is falsy. If b is truthy, a retains its original value. This operator can be useful when we want to update a variable only if a new value is falsy.

Conclusion:

The introduction of these new assignment operators can significantly enhance the readability and efficiency of JavaScript code. They provide a more concise way to handle common assignment scenarios, reducing the need for verbose if-statements and ternary operators. By adopting these operators, we can make JavaScript even more powerful and developer-friendly.

These scenarios seem pretty rare actually. Can you give some good examples from real-world code?

Thank you for your feedback. I'm actually gathering some statistics from the codebases I work with. I'm going to add it to this thread soon.

But so far I can say that more often I come across another form of re-presentation of the same case:

let a = 'some default value';

if (b) {
  a = b;
}

which would be possible to replace with just a =?? b;

In my research, I've undertaken an evaluation to estimate the potential benefits of introducing new syntax improvements in JavaScript. On one side, I've analyzed the number of cases where the proposed syntax enhancements could be utilized. On the other side, I've examined the prevalence of Nullish coalescing assignment, logical OR assignment, and
logical AND assignments and identified scenarios where it is currently used or could be employed.

PART I

I've crafted a set of regular expressions with the aim of quantifying the instances where implementing the proposed new syntax is feasible. These expressions are designed to accommodate various coding styles, accounting for differences such as spacing variations and line breaks.

  1. Identifies instances where a variable is assigned a value based on a truthy condition within an if statement block.
if\s*\(\s*((\w+\.)*\w+)\s*\)\s*\{\s*\n*\s*(\w+\.)*\w+\s*=\s*\1;\s*\n*\s*\}(?!\s*else)

Example cases:

if (b) {
  a = b;
}

if (objB.prop2) {
  objA.prop1 = objB.prop2;
}

if (b) { a = b; }

if (objB.prop2) { objA.prop1 = objB.prop2; }

1a) Extends Regex 1 to specifically target cases where the condition involves checking inequality with null or undefined.

if\s*\(\s*((\w+\.)*\w+)\s*!=+\s*(null|undefined)\s*\)\s*\{\s*\n*\s*(\w+\.)*\w+\s*=\s*\1;\s*\n*\s*\}(?!\s*else)

Example cases:

if (b !== null) { // !== or !=, null or undefined
  a = b;
}

if (objB.prop2 !== null) {
  objA.prop1 = objB.prop2;
}

if (b !== null) { a = b; }

if (objB.prop2 !== null) { objA.prop1 = objB.prop2; }
  1. Identifies cases of single-line variable assignments within an if statement block.
if\s*\(\s*((\w+\.)*\w+)\s*\)\s*\n*\s*(\w+\.)*\w+\s*=\s*\1;\s*\n*(?!\s*else)

Example cases:

if (b) a = b;

if (b)
    a = b;

if (objB.prop2) objA.prop1 = objB.prop2; // any level of nesting

if (objB.prop2)
    objA.prop1 = objB.prop2;

2a) Extends Regex 2 to specifically target cases involving inequality checks with null or undefined.

if\s*\(\s*((\w+\.)*\w+)\s*!=+\s*(null|undefined)\s*\)\s*\n*\s*(\w+\.)*\w+\s*=\s*\1;\s*\n*(?!\s*else)

Example cases:

if (b !== null) a = b;  // !== or !=, null or undefined

if (b !== null)
    a = b;

if (objB.prop2 !== null) objA.prop1 = objB.prop2; // any level of nesting

if (objB.prop2 !== null)
    objA.prop1 = objB.prop2;

Please note that I deliberately exclude the following two cases:

if (b) {
  a = b;
} else ... // some alternative logic

if (b) {
  ... // some other logic
  a = b;
  ... // some other logic
}

These exclusions are made because such cases typically do not present opportunities for benefiting from the proposed syntax.

  1. Matches instances where a variable is assigned the result of a nullish coalescing operation (??).
[\s\n](\w+\.\w+)\s*=(\s*((\w+\.)*\w+)\s*\?\?\s*)\1;

Example cases:

a = b ?? ... ?? a;

objA.prop1 = objB.prop2 ?? ... ?? objA.prop1;
  1. Identifies cases where a variable is assigned the result of a logical OR operation (||).
[\s\n](\w+\.\w+)\s*=(\s*((\w+\.)*\w+)\s*\|\|\s*)\1;

Example cases:

a = b || ... || a;

objA.prop1 = objB.prop2 || ... || objA.prop1;
  1. Matches instances where a variable is assigned the result of a logical AND operation (&&).
[\s\n](\w+\.\w+)\s*=(\s*((\w+\.)*\w+)\s*&&\s*)\1;

Example cases:

a = b && ... && a;

objA.prop1 = objB.prop2 && ... && objA.prop1;

After conducting a search using these regular expressions in VSCode across several locally accessible projects, here are the results:

| Project   | regex 1 | regex 1a | regex 2 | regex 2a | regex 3 | regex 4 | regex 5 | Total |
|-----------|---------|----------|---------|----------|---------|---------|---------|-------|
| Project 1 | 61      | 1        | 19      | 0        | 4       | 7       | 0       | 92    |
| Project 2 | 59      | 2        | 14      | 0        | 0       | 3       | 0       | 78    |
| Project 3 | 2       | 0        | 0       | 0        | 0       | 0       | 0       | 2     |
| Total     | 122     | 3        | 33      | 0        | 4       | 10      | 0       | 172   |

PART II

In this section, I focus on exploring how often Nullish coalescing assignment and logical assignments are used or could be useful. Using the following search patterns, I will look through code to find examples of these features being used.

  1. Identifies cases where a variable is assigned a value when it is falsy within an if statement block.
if\s*\(\s*!((\w+\.)*\w+)\s*\)\s*\{\s*\n*\s*\1\s*=\s*(\w+\.)*\w+;\s*\n*\s*\}(?!\s*else)

Example cases:

if (!a) {
  a = b;
}

if (!objA.prop1) {
  objA.prop1 = objB.prop2;
}

if (!a) { a = b; }

if (!objA.prop1) { objA.prop1 = objB.prop2; }

1a) Targets cases where a variable is assigned a value when it is explicitly equal to null or undefined within an if statement block.

if\s*\(\s*((\w+\.)*\w+)\s*=+\s*(null|undefined)\s*\)\s*\{\s*\n*\s*\1\s*=\s*(\w+\.)*\w+;\s*\n*\s*\}(?!\s*else)

Example cases:

if (a === null) { // === or ==, null or undefined
  a = b;
}

if (objA.prop1 === null) {
  objA.prop1 = objB.prop2;
}

if (a === null) { a = b; }

if (objA.prop1 === null) { objA.prop1 = objB.prop2; }
  1. Matches instances of single-line variable assignments within an if statement block.
if\s*\(!\s*((\w+\.)*\w+)\s*\)\s*\n*\s*\1\s*=\s*(\w+\.)*\w+;\s*\n*(?!\s*else)

Example cases:

if (!a) a = b;

if (!a)
    a = b;

if (!objA.prop1) objA.prop1 = objB.prop2; // any level of nesting

if (!objA.prop1)
    objA.prop1 = objB.prop2;

2a) Targets single-line variable assignments within an if statement block when the condition checks for equality with null or undefined.

if\s*\(\s*((\w+\.)*\w+)\s*=+\s*(null|undefined)\s*\)\s*\n*\s*\1\s*=\s*(\w+\.)*\w+;\s*\n*(?!\s*else)

Example cases:

if (a === null) a = b; // === or ==, null or undefined

if (a === null)
    a = b;

if (objA.prop1 === null) objA.prop1 = objB.prop2; // any level of nesting

if (objA.prop1 === null)
    objA.prop1 = objB.prop2;
  1. Matches nullish coalescing assignments.
[\s\n](\w+\.\w+)\s*=\s*\1(\s*\?\?\s*(\w+\.)*\w+)+;

Example cases:

a = a ?? b ?? ...;

objA.prop1 = objA.prop1 ?? objB.prop2 ?? ...;
  1. Identifies cases of logical OR assignments.
[\s\n](\w+\.\w+)\s*=\s*\1(\s*\|\|\s*(\w+\.)*\w+)+;

Example cases:

a = a || b || ...;

objA.prop1 = objA.prop1 || objB.prop2 || ...;
  1. Matches cases of logical AND assignments.
[\s\n](\w+\.\w+)\s*=\s*\1(\s*&&\s*(\w+\.)*\w+)+;

Example cases:

a = a && b && ...;

objA.prop1 = objA.prop1 && objB.prop2 && ...;
  1. Identifies nullish coalescing assignments with the ??= operator.
[\s\n](\w+\.\w+)*\s*\?\?=

Example cases:

a ??= ...;

objA.prop1 ??= ...;
  1. Matches logical OR assignments with the ||= operator.
[\s\n](\w+\.\w+)*\s*\|\|=

Example cases:

a ||= ...;

objA.prop1 ||= ...;
  1. Identifies logical AND assignments with the &&= operator.
[\s\n](\w+\.\w+)*\s*&&=

Example cases:

a &&= ...;

objA.prop1 &&= ...;

After conducting a search using these regular expressions in VSCode across same locally accessible projects, here are the results:

| Project   | regex 1 | regex 1a | regex 2 | regex 2a | regex 3 | regex 4 | regex 5 | regex 6 | regex 7 | regex 8 | Total |
|-----------|---------|----------|---------|----------|---------|---------|---------|---------|---------|---------|-------|
| Project 1 | 17      | 0        | 0       | 0        | 0       | 2       | 0       | 0       | 0       | 0       | 19    |
| Project 2 | 8       | 1        | 6       | 0        | 0       | 2       | 0       | 0       | 1       | 0       | 18    |
| Project 3 | 1       | 2        | 1       | 0        | 0       | 1       | 0       | 0       | 1       | 0       | 6     |
| Total     | 26      | 3        | 7       | 0        | 0       | 5       | 0       | 0       | 2       | 0       | 43    |

In conclusion, the results of my preliminary local research suggest that the newly proposed syntax enhancements have even greater potential for adoption compared to the existing syntax of Nullish coalescing assignment and logical assignments. However, to further validate these findings and ensure objectivity, I encourage others to conduct similar analyses in their own projects. Additionally, exploring open-source projects could provide valuable insights into the broader adoption of these syntax enhancements in the JavaScript community.