I recently wrote about new features introduced in ES2020... While some of these opportunities are interesting, there are none that deserve to be called "revolutionary". This is understandable given the fact that the JS specification is updated quite often these days. It turns out that those working on the standard simply have fewer opportunities to constantly introduce something special into the language, like ES6 modules or arrow functions. But this does not mean that something exclusively new will not eventually appear in the language. As a matter of fact, this is what I want to talk about today. I would like to talk about 4 possibilities that, in the future, can be called revolutionary. They are now at different stages of the process.
coordination of proposals. This, on the one hand, means that we may never see them in JavaScript and not see them, and on the other hand, the presence of such sentences gives us hope that we will, nevertheless, someday meet them in the language.
Decorators
We'll start with the feature that is probably the most frequently asked to be included in the language, and around which quite a lot of buzz has been raised. A couple of years ago, they wrote about her literally everywhere. It's about decorators .
You may already be familiar with decorators. Especially if you write in TypeScript. This is, in essence, a metaprogramming concept aimed at giving the developer the ability to "inject" their own functionality into classes, into their individual fields and methods, ultimately making the classes programmable.
Take a look at the following example:
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
Here I decided to proceed with caution and gave an example of using TypeScript decorators . I did this mainly to show the general idea. In the above code snippet, we created a decorator
sealed
and applied it to the class Greeter
. As you can see, a decorator is simply a function that has access to the constructor of the class it is applied to (this is the target). We use a reference to a constructor, as well as a method Object.seal()
to make the class non-extensible.
In order to apply a decorator to a class, we write the name of the decorator with an icon
@
just before the class declaration. As a result, it turns out that before the class declaration appears a construction of the form @[name]
, which in our case looks like @sealed
.
You can check the decorator's functionality by compiling this TS code with the option enabled
experimentalDecorators
and trying to change the class prototype:
Greeter.prototype.test = "test"; // ERROR
As a result, you should now have a general understanding of why decorators are needed at all. But I would like to touch upon one difficult question here. It concerns the state of the approval of the proposal for decorators.
I decided to use TypeScript to demonstrate decorators for a good reason. The point is that a proposal for embedding decorators in JavaScript has been around a few years ago. And it is now "only" at the 2nd stage of agreement out of 4. Both the syntax and the capabilities of the decorators from this proposal are constantly being changed. But that doesn't stop the JS community from using this concept. In order to be convinced of this, it is enough to look at huge open source projects like TypeScript or Angular v2 +.
True, all this, over time, and as the proposal develops, leads to a problem related to the incompatibility of specifications. Namely, the decorator specification has evolved a lot since the proposal was made, but many projects still haven't implemented it. The TypeScript example shown above is a demonstration of the implementation of an older version of the proposal. The same can be said for Angular, and even Babel (although, in the case of Babel, we can say that work is now underway to implement a newer version of this specification). In general, the newer version of the proposal, which uses a keyword
decorator
and syntax suitable for linking, has yet to find any noticeable use.
The bottom line is that decorators have the potential to change the way we write code. And these changes are already showing themselves, even though decorators are still in the early stages. However, given the current state of affairs, decorators only fragment the community, and I believe they are not yet ready for really serious use. I would advise those who are interested in decorators to wait a bit before introducing them into production. My recommendation, however, does not apply to those using frameworks that use decorators (like Angular).
Realms
Now let's slow down a bit and talk about one feature that's not as complex as decorators. We are talking about areas .
You may have already been in situations where you need to run your own code, or code from a third-party developer, but at the same time do it in such a way that this code would not affect the global environment. Many libraries, especially browser ones, work through the global object
window
. As a result, they can interfere with each other in the event that the project uses too many libraries beyond the control of the developer. This can lead to errors.
The current browser solution to this problem is to use the elements
<iframe>
, and in some special cases - in the use of web workers. In the Node.js environment, the same problem is solved using a module vm
or using child processes . The Realms API is designed to solve such problems.
This API aims to allow developers to create separate global environments called scopes. Each such area has its own global entities. Take a look at the following example:
var x = 39;
const realm = new Realm();
realm.globalThis.x; // undefined
realm.globalThis.x = 42; // 42
realm.globalThis.x; // 42
x; // 39
Here we create a new object
Realm
using the appropriate constructor. From now on, we have full access to the new scope and its global objects through a property globalThis
(introduced in ES2020). Here you can see that the variables of the main "incubator" are separated from the variables in the scope we created.
Overall, the Realms API is planned as a very simple mechanism, but it is a useful mechanism. This API has a very specific set of use cases. It doesn't give us a higher level of security, or the ability to multithreaded code. But it perfectly, without creating unnecessary load on the system, copes with its main task, with providing basic capabilities for creating isolated environments.
The Realms API proposal is currently in stage 2 of negotiation. When it eventually hits the standard, one would expect it to be used in "heavy" libraries that rely on the global scope, in online sandboxed code editors, in various applications targeting testing.
Do expressions
JavaScript syntax, like the syntax of most programming languages, includes statements and expressions. The most noticeable difference between these constructs is that expressions can be used as values ββ(that is, they can be assigned to variables, passed to functions, and so on), while statements cannot be used as such.
Because of this difference, expressions are the most preferred choice for cleaner, more compact code. In JavaScript, you can see this by looking at the popularity of function expressions, which include arrow functions, versus function declarations, function statements. The same situation is seen if we compare the methods for iterating over arrays (like
forEach()
) with cycles. The same is true for more advanced programmers when comparing a ternary operator and a statement if
.
The do-expression proposal , currently under negotiation stage 1, aims to further enhance the capabilities of JS expressions. And, by the way, do not confuse the concept of "do-expression" with loops
doβ¦while
, since they are completely different things.
Here's an example:
let x = do {
if (foo()) {
f();
} else if (bar()) {
g();
} else {
h();
}
};
Here's the syntax from the do-expression clause. In general, we have before us a piece of JS code wrapped in a construction
do {}
. The last expression in this construct is "returned" as the final value of the entire do expression.
A similar (but not identical) effect is achievable using an IIFE (Immediately Invoked Function Expression). But in the case of do expressions, their compact syntax seems very attractive. Here, with similar functionality, you do not need either
return
, or any ugly auxiliary structures like(() => {})()
... This is why I believe that once do expressions get into the standard, their impact on JavaScript will be comparable to that of arrow functions. Convenience of expressions and friendly syntax, so to speak, in one package, look very tempting.
Pattern matching
This opportunity is the last in this material, but it is far from the last in importance. This is a proposal aimed at introducing a pattern matching mechanism into the language .
You may be familiar with the JS instruction
switch
. It is similar to if-else
, but its options are a little more limited, and it is certainly better suited for organizing the choice of one of the many alternatives. This is how it looks:
switch (value) {
case 1:
// ...
break;
case 2:
// ...
break;
case 3:
// ...
break;
default:
// ...
break;
}
Personally, I think an instruction is
switch
weaker than an instruction if
, since it switch
can compare what is passed to it only with specific values. This limitation can be circumvented , but I cannot think of why. In addition, the instruction is switch
overloaded with auxiliary elements. In particular, we are talking about instructions break
.
The pattern matching mechanism can be thought of as a more functional, expression-based, and potentially more versatile version of a statement
switch
. Rather than simply comparing values, the pattern matching mechanism allows the developer to compare values ββagainst custom patterns (templates) that are highly customizable. Here is a code snippet demonstrating an example of the proposed API:
const getLength = vector => case (vector) {
when { x, y, z } -> Math.hypot(x, y, z)
when { x, y } -> Math.hypot(x, y)
when [...etc] -> vector.length
}
getLength({x: 1, y: 2, z: 3})
It uses a syntax that is quite unusual for JavaScript (although it is based on the syntax found in languages ββsuch as Rust or Scala ), which has some similarities with the instruction already known to us
switch
. Here, instead of a keyword, a word switch
is used case
that marks the beginning of the block in which the value is checked. Then, inside the block, using the keywordwhen
, we describe the templates with which we want to validate values. The syntax of templates resembles the syntax of the object destructuring mechanism already available in the language. Values ββcan be compared with objects containing selected properties, they can be compared with property values ββof objects and with many other entities. To learn more about this mechanism - take a look at this document.
After the description of the template, there is an arrow ("flat arrow",
->
) pointing to the expression (in perspective - even to a different value), which should be evaluated when finding a match with the pattern.
I believe that the presence of such capabilities in JS will allow us to write, so to speak, new generation code. However, the syntax proposed now seems a bit cumbersome to me, since it introduces many completely new constructs into the language. And the fact that this proposal is still at the 1st stage of agreement makes me think that it still has room for improvement. This feature looks very promising, but it still has a long way to go before it makes it into the official JS spec.
Outcome
This concludes my story about the revolutionary features of JavaScript, which we may see in the language in the future. There are other similar possibilities, for example, proposals for an external standard library and a pipelined operator . But I chose for this material only what seemed to me the most interesting. Keep in mind that these opportunities are still in the proposal stage. They can change over time. Or it may happen that they never get into the standard. But if you, in any case, want to be among those who use such opportunities before others, I advise you to take a closer look at projects such as Babel... These projects give birth to a lot of JS sentences (especially those related to syntax). This allows anyone to experiment with the latest features long before they appear in language implementations.
What features do you miss the most in JavaScript?