ES10 is still only a draft. But with the exception of Object.fromEntries, most features are already implemented in Chrome, so why not start exploring it early? By the time all browsers start supporting it, it’s only a matter of time before you have a head start. For those interested in exploring ES10, this is a non-alien guide.

ES10 is not as important as ES6 in terms of new language features, but it does add some interesting things (some of which don’t work in the current version of the browser: 02/20/2019)

The most popular feature in ES6 is the arrow function, but what about ES10?

BigInt – An arbitrary precision integer

BigInt is the seventh primitive type.

BigInt is an integer of arbitrary precision. This means that the variable can now represent 2^53 numbers. And the maximum is 9007199254740992.

const b = 1n; // Append n to create a BigInt

The value of an integer in the past is greater than 9007199254740992. If it is exceeded, the value is locked to MAX_SAFE_INTEGER + 1:

const limit = Number.MAX_SAFE_INTEGER;
⇨ 9007199254740991
limit + 1; 
⇨ 9007199254740992
limit + 2; 
⇨ 9007199254740992 <--- MAX_SAFE_INTEGER + 1 exceeded
const larger = 9007199254740991n;
⇨ 9007199254740991n
const integer = BigInt(9007199254740991); // initialize with number9007199254740991n
const same = BigInt("9007199254740991"); // initialize with "string"9007199254740991n
Copy the code

typeof

typeof 10;
⇨ 'number'
typeof 10n;
⇨ 'bigint'
Copy the code

= = = = =

10n === BigInt(10);
⇨ true
10n == 10;
⇨ true
Copy the code

* /

200n / 10N ⇨20n
200n / 20
⇨ Uncaught TypeError:
   Cannot mix BigInt and other types, use explicit conversions <
Copy the code

– +

- 100.N ⇨- 100.n
+100N ⇨ UncaughtTypeError:
  Cannot convert a BigInt value to a number
Copy the code

By the time you read about this matchAll, it will probably be officially implemented in Chrome C73 – if not, it’s still worth a look. Especially if you’re a regular expression junkie.

string.prototype.matchAll()

If you Google “javascript string match all”, the first result might be something like How do I write a regular expression to “match all”? . The top results suggest string. match matches with /g after the regular expression or RegExp. Exc or RegExp.

First, let’s look at how the old specification works.

String.match, match returns only the first String argument that matches.

let string = 'Hello'
let matches = string.match('l')
console.log(matches[0]) // 'l'
Copy the code

The result of matching is a single ‘l’. (Note: the result of a match match is stored in matches[0], not matches), and a search for match ‘l’ in the string ‘hello’ returns only ‘l’. Using the regexp parameter gives the same result.

We replace the character ‘l’ with the expression /l/:

let string = 'Hello'
let matches = string.match(/l/)
console.log(matches[0]) // 'l'
Copy the code

Add/g

String.match returns multiple matches using the regular expression with the /g tag.

let string = 'Hello'
let ret = string.match(/l/g) // ['l'.'l']
Copy the code

Great… We got multiple matches in environments below ES10, and they were valid all the time.

So why the whole new matchAll approach? Before we answer this question in more detail, let’s take a look at the Capture Group. If nothing else, you might learn something new about regular expressions.

Regular expression capture group

Capturing groups in a regular expression simply extracts matches in () brackets. You can capture groups from /regex/.exec(string) and String.match.

Typically, capture groups are created in matching rules. Create groups properties on output objects such as: (? < name >). To create a new group name, simply add (?

) property, the grouping (mode) match will become the groups.name attached to the match object.

Look at a practical example:

String sample matching

match.groups.color & match.groups.bird

const string = 'black*raven lime*parrot white*seagull'const regex = /(? <color>.*?) A \ * (? <bird>[a-z0-9]+)/gwhile (match = regex.exec(string) {
    let value = match[0]
    let index = match.index
    let input = match.input
    console.log(`${value} at ${index} with '${input}'`)
    console.log(match.groups.color)
    console.log(match.groups.bird)
}
Copy the code

The regex.exec method needs to be called several times to traverse the entire search result. When.exec is called in each iteration, the next result is displayed (it does not return all matches at once).

Console output:

black*raven at 0 with 'black*raven lime*parrot white*seagull'
black
raven
lime*parrot at 11 with 'black*raven lime*parrot white*seagull'
lime
parrot
white*seagull at 23 with 'black*raven lime*parrot white*seagull'
white
seagull
Copy the code

Here’s a weird one:

If you remove/g from this regular expression, you will always create an infinite loop on the first result. This was a great pain in the past. Imagine receiving a regular expression from some database, and you’re not sure if it has/g at the end. You have to check it first, etc.

Now we have enough background to answer this question:

It is best to use.matchAll()

  1. More elegant when using capture groups. Capture group knowledge with a portion of the regular expression that extracts pattern ().
  2. It returns an iterator instead of an array, which is useful by itself.
  3. You can use the extension operator… Turn iterators into arrays.
  4. itavoiduse/glogoRegular expression. Useful when retrieving unknown regular expressions from a database or external source and using them with old RegEx objects.
  5. useRegExpObject regular expressions cannot be created using dot (.) operator link.
  6. * * senior:RegExThe ** object tracks the interior of the last matched position.lastIndexProperty, which can be a destructive thing for complex cases.

.matchAll()How to work

This is a simple example.

We try to match all e and L of the string Hello. Since we return iterator, we use for… Of handles it.

// Match all occurrences of the letters: 'e'or'l'
let iterator = 'hello'.matchAll(/[el]/)
for (const match of iterator) {
    console.log(match)
}
Copy the code

As above, you can skip /g,.matchall doesn’t need it. Results:

[ 'e', index: 1, input: 'hello' ] // Iteration 1
[ 'l', index: 2, input: 'hello' ] // Iteration 2
[ 'l', index: 3, input: 'hello' ] // Iteration 3
Copy the code

Example using.matchall () capture group:.matchall () has all the benefits listed above, it is an iterator, so we can use it to loop, that’s the whole syntactic difference.

const string = 'black*raven lime*parrot white*seagull'; const regex = /(? <color>.*?) A \ * (? <bird>[a-z0-9]+)/;for (const match of string.matchAll(regex)) {
    let value = match[0];
    let index = match.index;
    let input = match.input;
    console.log(`${value} at ${index} with '${input}'`);
    console.log(match.groups.color);
    console.log(match.groups.bird);
}
Copy the code

Note that the /g flag is removed, because.matchall () already implies it.

Result output:

black*raven at 0 with 'black*raven lime*parrot white*seagull'
black
raven
lime*parrot at 11 with 'black*raven lime*parrot white*seagull'
lime
parrot
white*seagull at 23 with 'black*raven lime*parrot white*seagull'
white
seagull
Copy the code

It is perhaps aesthetically very similar to the original regx.exec when the loop was implemented. But as mentioned earlier, this is the better approach for many of the reasons mentioned above. And deleting/g does not cause an infinite loop.

Dynamic import

You can now assign an import to a variable:

element.addEventListener('click', async () => {
    const module = await import('./api-scripts/button-click.js')
    module.clickEvent()
})
Copy the code

Array.flat()

Flat multidimensional array:

letMulti = [1, 2, 3, 4 and 6, [7,8,9, final three [10]]]]. multi.flat(); / / [6, Array (4)]. Multi flat () flat (); / / [1,2,3,4,5,6,7,8,9, Array (3)] multi. Flat () flat (), flat (); / / multi,2,3,4,5,6,7,8,9,10,11,12 [1]. The flat (Infinity); / /,2,3,4,5,6,7,8,9,10,11,12 [1]Copy the code

Array.flatMap()

let array = [1, 2, 3, 4, 5]
array.map(x => [x, x * 2])
Copy the code

To:

[Array(2), Array(2), Array(2)]
0: (2)[1, 2]
1: (2)[2, 4]
2: (2)[3, 6]
3: (2)[4, 8]
4: (2)[5, 10]
Copy the code

Flatten the array again:

array.flatMap(v => [v, v * 2])
[1, 2, 2, 4, 3, 6, 4, 8, 5, 10]
Copy the code

Object.fromEntries()

Converts a list of key-value pairs to objects.

let obj = { apple : 10, orange : 20, banana : 30 };
let entries = Object.entries(obj);
entries;
(3) [Array(2), Array(2), Array(2)]
 0: (2) ["apple", 10]
 1: (2) ["orange", 20]
 2: (2) ["banana", 30]
let fromEntries = Object.fromEntries(entries);
{ apple: 10, orange: 20, banana: 30 }
Copy the code

String.trimStart() & String.trimEnd()

let greeting = " Space around ";
greeting.trimEnd();   // " Space around";
greeting.trimStart(); // "Space around ";
Copy the code

Well-formed json.stringify ()

This update fixes the handling of characters U + D800 through U + DFFF, sometimes into JSON strings. This can be a problem because json.stringify may return these numbers formatted as values with no EQUIVALENT UTF-8 characters. However, the JSON format requires UTF-8 encoding.

JSON objects can be used to parse JSON formats (but also more.) JavaScript JSON objects also have stringify and parse methods.

This parsing method applies to a well-formed JSON string, such as:

'{" prop1 ": 1, "prop2" : 2}'; // A well-formed JSON format string

Note that creating a string with the correct JSON format absolutely requires double quotes around the attribute name. The lack of… Or any other type of quotes will not produce well-formed JSON.

'{ “prop1” : 1, "meth" : () => {}}'; // Not JSON format string

The JSON string format is different from the object text…… It looks almost identical, but can use any type of quote around the attribute name, and can also include methods (methods not allowed in JSON format) :

Let object_literal = {property: 1, meth () => {}};

Anyway, everything seems to be fine. The first example looks compliant. But they are also simple examples that work without obstacles most of the time!

U + 2028 and U + 2029 characters

This is capture. EcmaScript prior to ES10 doesn’t actually fully support JSON. In the pre-ES10 era, unescaped line delimiter U + 2028 and paragraph delimiter U + 2029 characters were not accepted:

The same is true for all characters between U + D800 – U + DFFF

If these characters creep into your JSON-formatted string (from, say, a database record), you can end up spending hours trying to figure out why the rest of the program produced parsing errors.

So, if you pass eval to a string like “console.log(‘ hello ‘)” this will execute JavaScript statements (trying to convert through the actual code of the string). This is also similar to how json.parse will process your JSON strings.

The stability of the Array. The prototype. The sort ()

Previous implementations of V8 used an unstable quicksort algorithm for arrays containing more than 10 items.

A stable sorting algorithm is when two objects with equal keys appear in the sorted output in the same order as they appear in the unsorted input.

But that’s no longer the case. ES10 provides stable array sorting:

var fruit = [
    { name: "Apple",      count: 13, },
    { name: "Pear",       count: 12, },
    { name: "Banana",     count: 12, },
    { name: "Strawberry", count: 11, },
    { name: "Cherry",     count: 11, },
    { name: "Blackberry", count: 10, },
    { name: "Pineapple",  count: 10, }
];
// Create our own sort criteria function:
let my_sort = (a, b) => a.count - b.count;
// Perform stable ES10 sort:
let sorted = fruit.sort(my_sort);
console.log(sorted);
Copy the code

Console output (items appear in reverse order) :

New Function.toString()

Funcitons are objects, each Object has a. ToString () method because it originally exists in the Object. The prototype. The toString (). All objects (including functions) are inherited from prototype-based class inheritance. This means we already have the function.toString() method.

But ES10 takes a further attempt to standardize the string representation of all objects and built-in functions. The following new cases:

Classic example

function () { console.log('Hello there.'); }.toString();
Copy the code

Console output (function body in string format 🙂

function () { console.log('Hello there.'); }
Copy the code

Here are other examples:

Directly from the function name

Number.parseInt.toString();
⇨ function parseInt() { [native code] }
Copy the code

Binding context

function () { }.bind(0).toString();
⇨ function () { [native code] }
Copy the code

Built-in callable function objects

Symbol.toString();
⇨ function Symbol() { [native code] }
Copy the code

Dynamically generated functions

Function().toString();
⇨ function anonymous() {}
Copy the code

Dynamically generated generator function*

function* () { }.toString();
⇨ function* () {}Copy the code

prototype.toString

Function.prototype.toString.call({}); ⇨ Function. The prototype. ToString requires that'this' be a Function"
Copy the code

Optional Catch Binding

In the past, the catch clause in a try/catch statement required a variable.

Try/catch statements help us intercept errors at the terminal level:

Here’s a review:

try {
    // Call a non-existing function undefined_Function
    undefined_Function("I'm trying");
}
catch(error) {
    // Display the error if statements inside try above fail
    console.log( error ); // undefined_Function is undefined
}
Copy the code

In some cases, however, the required error variable is not used:

try {
    JSON.parse(text); // <--- this will fail with "text not defined"
    return true; <--- exit without error even if there is one
}
catch (redundant_sometmes) <--- this makes error variable redundant
{
    return false;
}
Copy the code

The person who wrote this code tried to exit the try clause by forcing it to true. But… This is not the case (as Douglas Massolari.).

(() => {
    try {
        JSON.parse(text)
        return true
    } catch(err) {
        return false}}) () = >false
Copy the code

In ES10, a Catch Error Binding is optional

You can now skip the error variable:

try {
    JSON.parse(text);
    return true;
}
catch
{
    return false;
}
Copy the code

Standardized globalThis object

Global this was not standardized prior to ES10.

In production code, you must manually add the following code to standardize global objects across multiple platforms.

var getGlobal = function () {
    if(typeof self ! = ='undefined') { return self; }
    if(typeof window ! = ='undefined') { return window; }
    if(typeof global ! = ='undefined') { return global; }
    throw new Error('unable to locate global object');
};
Copy the code

But even that doesn’t always work. So ES10 added the globalThis object, which should be accessed on any platform from now on:

// Access global array constructor globalThis.Array(0, 1, 2); ⇨ [0, 1, 2] // Similar to window.v = {flag:true } in <= ES5
globalThis.v = { flag: true}; console.log(globalThis.v); ⇨ {flag:true }
Copy the code

Symbol.description

Description is a read-only property that returns an optional description of the Symbol object.

let mySymbol = 'My Symbol';
let symObj = Symbol(mySymbol);
symObj; // Symbol(My Symbol)
String(symObj) === `Symbol(${mySymbol}) `); //true
symObj.description; // "My Symbol"
Copy the code

Hashbang syntax

Shebang Unix users will be familiar with AKA.

It specifies an interpreter (what will execute your JavaScript file?).

ES10 standardizes this. I won’t go into the details of this, because technically it’s not really a language feature. But it basically unifies the way JavaScript is executed on the server side.

$ ./index.js
Copy the code

Instead of:

$ node index.js
Copy the code

On a UNIx-like operating system.

ES10 Classes: private, static & public members

The new syntax character # (hash tag) is now directly in class body scope as wellconstructorAnd class methods are used to definevariables.functions.gettersandsetters

This is a rather pointless example, focusing only on the new syntax:

class Raven extends Bird {
    #state = { eggs: 10};
    // getter
    get #eggs() { 
        return state.eggs;
    }
    // setter
    set #eggs(value) {
        this.#state.eggs = value;
    }
    #lay() {
        this.#eggs++;
    }
    constructor() {
        super();
        this.#lay.bind(this);
    }
    #render() {
        /* paint UI */
    }
}
Copy the code

To be honest, I think it makes the language harder to read.

It’s still my favorite new feature, because I love classes in the C ++ era.

Summary and feedback

ES10 is a set of new features that haven’t had a chance to be fully explored in a production environment. If you have any corrections, suggestions or any other feedback, please let us know.

I often write a tutorial because I want to learn some subjects by myself. This is one of those times, with the help of resources that others have compiled:

Thanks to Sergey Podgornyy for writing this ES10 tutorial. Thanks to Selvaganesh for writing this ES10 tutorial.