# ES12 - ECMAScript 2021

### String.prototype.replaceAll()

The **`replaceAll()`** method returns a new string with all matches of a `pattern` replaced by a `replacement`. The `pattern` can be a string or a `RegExp`, and the `replacement` can be a string or a function to be called for each match.

```
const p = 'The quick brown fox jumps over the lazy dog. If the dog reacted, was it really lazy?';

console.log(p.replaceAll('dog', 'monkey'));
// expected output: "The quick brown fox jumps over the lazy monkey. If the monkey reacted, was it really lazy?"


// global flag required when calling replaceAll with regex
const regex = /Dog/ig;
console.log(p.replaceAll(regex, 'ferret'));
// expected output: "The quick brown fox jumps over the lazy ferret. If the ferret reacted, was it really lazy?"

```

### Promise.any()

`Promise.any()` takes an iterable of `Promise` objects and, as soon as one of the promises in the iterable fulfills, returns a single promise that resolves with the value from that promise. If no promises in the iterable fulfill (if all of the given promises are rejected), then the returned promise is rejected with an `AggregateError`, a new subclass of `Error` that groups together individual errors. Essentially, this method is the opposite of `Promise.all()`.

```
const promise1 = Promise.reject(0);
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'quick'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 500, 'slow'));

const promises = [promise1, promise2, promise3];

Promise.any(promises).then((value) => console.log(value));

// expected output: "quick"
```

### WeakRef

A **`WeakRef`** object lets you hold a weak reference to another object, without preventing that object from getting garbage-collected.

More information,

{% embed url="<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef>" %}

{% embed url="<https://github.com/tc39/proposal-weakrefs>" %}

### Logical Assignment Operators

The logical nullish assignment (`x ??= y`) operator only assigns if `x` is nullish (`null` or `undefined`).

#### Ex: 1

```
const a = { duration: 50 };

a.duration ??= 10;
console.log(a.duration);
// expected output: 50

a.speed ??= 25;
console.log(a.speed);
// expected output: 25

```

### Ex: 2

```
function config(options) {
  options.duration ??= 100;
  options.speed ??= 25;
  return options;
}

config({ duration: 125 }); // { duration: 125, speed: 25 }
config({}); // { duration: 100, speed: 25 }
```

### Logical AND assignment (&&=)

The logical AND assignment (`x &&= y`) operator only assigns if `x` is truthy.

```
let a = 1;
let b = 0;

a &&= 2;
console.log(a);
// expected output: 2

b &&= 2;
console.log(b);
// expected output: 0
```

### Logical OR assignment (||=)

The logical OR assignment (`x ||= y`) operator only assigns if `x` is falsy.

```
const a = { duration: 50, title: '' };

a.duration ||= 10;
console.log(a.duration);
// expected output: 50

a.title ||= 'title is empty.';
console.log(a.title);
// expected output: "title is empty"
```

### Numeric Separators

This feature enables developers to make their numeric literals more readable by creating a visual separation between groups of digits.

#### Regular Number Literals

```
let budget = 1_000_000_000_000;

// What is the value of `budget`? It's 1 trillion!
// 
// Let's confirm:
console.log(budget === 10 ** 12); // true
```

#### Binary Literals

```
let nibbles = 0b1010_0001_1000_0101;

// Is bit 7 on? It sure is!
// 0b1010_0001_1000_0101
//           ^
//
// We can double check: 
console.log(!!(nibbles & (1 << 7))); // true
```

#### Hex Literal

```
// Messages are sent as 24 bit values, but should be 
// treated as 3 distinct bytes:
let message = 0xA0_B0_C0;

// What's the value of the upper most byte? It's A0, or 160.
// We can confirm that:
let a = (message >> 16) & 0xFF; 
console.log(a.toString(16), a); // a0, 160

// What's the value of the middle byte? It's B0, or 176.
// Let's just make sure...
let b = (message >> 8) & 0xFF;
console.log(b.toString(16), b); // b0, 176

// What's the value of the lower most byte? It's C0, or 192.
// Again, let's prove that:
let c = message & 0xFF;
console.log(c.toString(16), b); // c0, 192
```

#### BigInt Literal

Numeric Separators are also available within BigInt literals.

```
// Verifying max signed 64 bit numbers:
const max = 2n ** (64n - 1n) - 1n;
console.log(max === 9_223_372_036_854_775_807n);
```

It can also be used similarly to Number literals

```
let budget = 1_000_000_000_000n;

// What is the value of `budget`? It's 1 trillion!
// 
// Let's confirm:
console.log(budget === BigInt(10 ** 12)); // true
```

Numeric Separators are only allowed between digits of BigInt literals, and not immediately before the BigInt `n` suffix.

```
// Valid
1_1n;
1_000n;
99999999_111111111_00000000n;

// Invalid: SyntaxError!
1_n;
0_n;
1000000_n;
1_000_000_n;
```

#### Octal Literal

While there isn't much of a benefit, numeric separators are available in the Octal Literal productions out of conventially being generally available in non-legacy productions. In other words, the intent for feature is to be broad available in non-legacy numeric literal types.

```
let x = 0o1234_5670;
let partA = (x & 0o7777_0000) >> 12; // 3 bits per digit
let partB = x & 0o0000_7777;
console.log(partA.toString(8)); // 1234
console.log(partB.toString(8)); // 5670
```
