TNS
VOXPOP
You’re most productive when…
A recent TNS post discussed the factors that make developers productive. You code best when:
The work is interesting to me.
0%
I get lots of uninterrupted work time.
0%
I am well-supported by a good toolset.
0%
I understand the entire code base.
0%
All of the above.
0%
I am equally productive all the time.
0%
Frontend Development / JavaScript / Software Development

The New JavaScript Features Coming in ECMAScript 2023

The next JavaScript update brings smaller additions familiar from other languages, but there are more significant developments in the wings. 
May 9th, 2023 6:00am by
Featued image for: The New JavaScript Features Coming in ECMAScript 2023
Image via Shutterstock 

This year’s annual update to ECMAScript, which formally standardizes the JavaScript language, will be approved in July 2023, but four proposals for new language features have already reached stage four. This means they’ve been signed off by the editors of ECMAScript in the TC39 working group that manages the language standard, have passed the test suite, and shipped in at least two implementations to check for real-world performance and issues.

Small but Helpful

Symbols as WeakMap keys fills in a small gap in the language, explained Daniel Ehrenberg, vice president of Ecma (the parent organisation of TC39) and a software engineer working on JavaScript developer experience at Bloomberg, who worked on the proposal. Introduced in ECMAScript 2015, WeakMap lets you extend an object with extra properties (for example, to keep track of how often the object is used) without worrying about creating a memory leak, because the key-value pairs in a WeakMap can be garbage collected.

Initially, you could only use objects as keys in a WeakMap, but you want the keys to be unique “and symbols were defined as a new immutable way, that cannot be recreated, so having those as a unique key in the weak map makes a lot more sense”, developer advocate and browser engineer Chris Heilmann told us. This integrates symbols more with these new data structures and might well increase usage of them.

Two of the proposals improve working with arrays, which he notes are becoming increasingly powerful in JavaScript, avoiding the need to write functions and loop over data to process it.

“Now you can do a filter or map, and just have a one-liner for something that was super complex in the past.”

Change Array by Copy gives developers new methods for sorting, reversing and overwriting data without mutating the array it’s stored in. “You’ve always been able to sort arrays, but when you call a sort function it would change the current array; and in functional programming and the functional patterns that have become very popular [in JavaScript], people like to avoid mutations,” TC39 co-chair and head of Bloomberg’s JavaScript Infrastructure and Tooling team Rob Palmer explained.

This proposal lets developers call a method to change a single element in the array, using with or splice, and get a new array with that single change — or sort and reverse an array into a fresh array but leave the original array unmodified. This is simpler for developers because it makes array and tuple behavior more consistent, Heilmann pointed out. “The inconsistency between whether array prototypes change the original array or not is something that drove me nuts in PHP. You do a conversion, send it to a variable and then there’s nothing in the variable, because some functions don’t change the original one and others do change it. Any consistency we can bring to things so people don’t have to look it up every day is a very good idea. And anything that allows me to not have to deal with index numbers and shift them around is also a good thing!”

Array find from last also does exactly what the name suggests, returning matching elements in an array starting at the end and working back, which can improve performance — or save writing extra code. “If you have a huge array, it’s really beneficial because you don’t have to look through the whole thing or reverse it before you look it up, so you don’t have to make a temporary duplicate — which developers do all the time,” Heilmann explained.

Most comments in JavaScript are there for developers working in the source code, to document how it works or record why it was written that way. Hashbang comments, which start with #!, are for specifying the path to the JavaScript interpreter that you want to use to run the script or module that follows the comment (a convention inherited from UNIX script files). CLI JavaScript hosts like Node.js already strip the hashbang out and pass the valid code onto the JavaScript engine, but putting this in the standard moves that responsibility to the JavaScript engine and makes sure it’s done in a uniform way.

Making hashbang grammar official in JavaScript gives it more consistency with the rest of the languages out there, he noted.

While serverside JavaScript is far from new, he said, “it feels to me like JavaScript has finally arrived as a serverside language with this, because when I think of Perl or PHP or all the other languages, you always have the hashbang.”

Although it’s another small change, it’s possible this will make it easier for JavaScript to participate in the AI and machine learning ecosystem, where Python is currently the dominant language.

Larger Proposals

These four proposals are very likely to be everything we see in ECMAScript 2023, which Ehrenberg noted is a small update, but there are also some important larger proposals that have already reached stage three (which means the spec has been agreed, but can’t be developed further without a full test suite and the real world experience of shipping the feature in at least two implementations).

Reaching stage three isn’t a guarantee that a feature will make it into the standard (because the implantations can reveal that changes need to be made). But iterator helpers, Temporal, explicit resource management and decorators are all stage three proposals making good progress that could be on track for ECMAScript 2024.

Iterator Helpers (and the companion stage two proposal for async iterator helpers) aim to make extremely large (including possibly infinite but enumerable data sets) as easy to work with as finite data structures like arrays. This includes methods like find, filter, map and reduce, which Python developers will be familiar with from generator expressions and itertools (and are available for JavaScript developers through libraries like lodash). “You can have an iterator and then map or for each or check whether some elements are there,” Ehrenberg explains.

Like change array by copy and hashbang grammar, this again brings useful options from other languages, because it’s the kind of feature that’s already widely used in languages like Python, Rust and C#.

“I feel like we’re making pretty good progress towards catching up with Python from fifteen or twenty years ago.”

Almost Time for Temporal

We’re still waiting for Temporal, which former ECMAScript co-chair Brian Terlson once described to us as “the replacement for our broken Date object” (other developers call Date “full of many of the biggest gotchas in JavaScript”). This eagerly awaited top-level namespace for a new date and time API that covers the full range of date, time, time zones, calendars and even public holidays worldwide will give developers far better options for working with the complexities of dates and times.

Although Temporal reached stage 3 in 2021, it’s been waiting for the Internet Engineering Task Force (IETF) to standardize string formats used for calendar and time zone annotations. While there were hopes that it would be completed in 2022, it’s still in draft stage. However, there are no major open issues and Carsten Bormann, one of the editors of the IETF date format proposal, told The New Stack that he believes it’s ready for IETF last call. The delay has been down to procedural questions about amending RFC 3339, internet timestamps, rather than any issues with Temporal or the IETF date and time formats it will use, and that’s being worked through, he said. “We have wide agreement on the parts that Temporal needs; we just need to clear that process hurdle.”

It’s still possible that there could be, for example, changes to the calendar format Temporal uses, but developers can start using Temporal now with polyfills (although you may not want to use that in production). Once the IETF draft is officially adopted, there will still need to be two implementations before it can reach stage four but a lot of that work is already underway.

“I’m really hopeful that this will be the year when we will see Temporal ship in at least one browser.”

“This is being implemented so many times,” Ehrenberg told us. “The implementation is in progress in V8, in [WebKit’s] JSC, in SpiderMonkey; in LibJS, the Serenity OS JavaScript engine, they have a pretty complete Temporal implementation and there are multiple polyfills. In addition to the IETF status, there have also been a number of small bug fixes that have been getting in, based on things that we’ve learned over the course of implementing the feature.”

“Hopefully, in the next few months we will be coming to an end with those bug fixes. And I’m really hopeful that this will be the year when we will see Temporal ship in at least one browser.”

While Temporal isn’t one of the priorities for this year’s Interop browser compatibility project, it did get a lot of votes from developers as an API to consider. “This is visible to browsers — to everyone — that this is high priority,” Ehrenberg said.

Delivering Decorators

The TC39 working group has spent more than five years working on different iterations of the Decorators proposal: a way of adding functionality to an object without altering its original code or affecting other objects from the same class. Decorated functions are available in other languages, like Python and C#, and JavaScript developers have been using transpilers like Babel and TypeScript to get them. Those differ slightly from what the ECMAScript Decorators proposal will finally deliver, but with the help of a proposal from the TypeScript team, TC39 was able to avoid a breaking change.

“A lot of people are using experimental TypeScript decorators or Babel legacy decorators,” Ehrenberg noted: “in either case, you need to explicitly opt into it, but a lot of frameworks do use decorators and do have presets that include them — and those original decorators are a little bit different from what ends up being stage three Decorators.”

“We went through many iterations of the Decorator proposal and we finally arrived at one that we could agree met both the use cases and the transition paths that were needed from previous decorators and the implementability concerns from browsers. We were finally able to triangulate all of that. It does mean that there are some differences, but at the same time we’ve really tried to make sure that the transition is smooth.”

For example, when you export a class that has a decorator, the first Decorators proposal put the decorator before the export keyword — but a later version of the proposal changed the syntax, putting the decorator after the export.

“A lot of the community was pretty upset about the change because it would have transition costs and there were lots of strong opinions in both directions. And at the very last minute, we decided, you know what, you’re allowed to do either — but not both. In one particular exported class declaration, the decorators can come either before or after the exported keyword, because we saw that the transition path from existing use of decorators was important. We want to enable incremental adoption and treat the existing ecosystem as real: we’re not designing this in a vacuum.”

Palmer credits the TypeScript team with putting in extra effort to make sure that TypeScript and JavaScript continue to be aligned. Ehrenberg agreed.

“There was a scary moment where we thought that TypeScript might ship decorator before export without JavaScript allowing it; and I’m really glad that just in time, we were able to convince everyone to agree on the same thing. That’s the birth of standards.”

There will be a slight difference in behavior depending on which order you pick: If you put the decorator before the export keyword, then it won’t be included in the Function.prototype.toString() text. If the decorator comes after export or export default (or is in a class that isn’t exported), it will be included in the string.

Making Resource Management Obvious

Having garbage collection doesn’t mean that JavaScript developers don’t need to think about managing memory and cleaning up resources, like file handles and network requests that are no longer needed. Some of the options for doing that work differ depending on where your code will run: you return a JavaScript iterator but close a Node.js file handle. And they depend on developers remembering to write the code and getting the code right.

“This makes it difficult to translate front-end development skills, where you might primarily work with the DOM, to back-end development, where you might be working with something like Node’s API, and vice versa. This inconsistency also makes it difficult for package authors to build lifetime management into their packages in a way that allows for reuse both on the web and on the server,” the creator of the proposal, Ron Buckton, told us.

Explicit Resource Management adds a new using statement (or await using for async code) to JavaScript, that’s similar to the with statement in Python or using in C#. Like const, it uses block scoping which developers will be familiar with since it’s been in JavaScript since ECMAScript 2015. You can open a resource like a file with using, work with the file, and then at the end of the block of code, the file will be automatically closed by the Symbol.dispose or Symbol.asyncDispose method in the using declaration.

“If closing the file means persisting something to a database you can make sure that you wait for that persistence to happen,” Ehrenberg explained.

If you need to compose multiple resources that will be used and then disposed of, there are container classes — DisposableStack and AsyncDisposableStack — which Buckton says were inspired by Python’s ExitStack and AsyncExitStack — that also let you work with existing objects that don’t yet use the new API.

The asynchronous version, awaitusing, was temporarily split off to a separate Async Explicit Resource Management proposal, because the syntax for that wasn’t as easy to decide on. Now it’s been agreed and has also reached stage three, so the proposals are being combined again and implementations are currently underway, Buckton says. According to Palmer:

“This is great for robust, efficient code, to really make sure you’re cleaning up your resources at the correct time.”

“I think this will be a big win for JavaScript developers, because previously, to get this effect reliably, you had to use try finally statements, which people would often forget to do,” Ehrenberg added. “You want to make sure to dispose of the resource, even if an exception is thrown.”

The feature is called “explicit” to remind developers that the resource cleanup will be done immediately and explicitly, as opposed to the implicit and somewhat opaque resource management you get with WeakMap, WeakRef, FinalizationRegistry or garbage collection. Using gives you an explicit, well-defined lifetime for an object that you know will be cleaned up in a timely way, so you can avoid race conditions, if you’re closing and reopening a file or committing transactions to a database.

“The garbage collector can run at weird and magical times, and you cannot rely on the timing,” Palmer warned.

It’s also not consistent across environments. “All JavaScript engines reserve the right to have reference leaks whenever they feel like it and they do have reference leaks at different times to each other,” Ehrenberg added.

“There are a lot of use cases for explicit resource management, from file IO and Stream lifetime management, to logging and tracing, to thread synchronization and locking, async coordination, transactions, memory management/resource pooling, and more,” Buckton said.

It will be particularly important for resources that have a significant impact on performance, but also drain battery. “I’m hoping that, as this proposal gets adopted by various hosts, we’ll soon be able to use ‘using’ and ‘await using’ with WebGPU and other DOM APIs where resource lifetime and memory management are extremely important, especially on mobile devices.”

Building on What’s New

Having proposals become part of ECMAScript doesn’t mean they don’t carry on developing, as implementers get more experience with them — and as new language features offer ways to improve them.

After a good many years, class fields (including private fields) was included in ECMAScript 2022, “but even though they’ve been shipping in browsers for years, some of the Node community found that there were some performance penalties in using these,” Palmer told us. To address that, Bloomberg funded Igalia to optimize private field performance in V8. “Now private fields access is now at least as fast as public fields and sometimes it’s even faster.”

Other work made it easier for developers to work with private fields by making them accessible inside the Chrome developer tools. From the top level of the console, you can now jump into private fields or look into them while inspecting an object. That doesn’t break any security boundaries, Palmer noted, because you’re in a development environment: “it makes life easier for the developer, and they are entitled to see what’s inside the class”.

In the future, Ehrenberg suggested, there might be a capability for authorized code to look into private fields, based on the stage three decorators proposal, which has features that aren’t in the existing decorators features in Babel and TypeScript. “When you decorate a private field or method, that decorator is granted the capability to look at that private field or method, so it can then share that capability with some other cooperating piece of code,” he explained.

“The new decorators provide a path towards more expressive private fields.”

As always, there are other interesting proposals that will take longer to reach the language, like type annotations, AsyncContext and internationalization work that — along with Temporal — will replace some commonly used but large libraries with well-designed, ergonomic APIs built into the language. There are also higher-level initiatives around standardizing JavaScript runtimes, as well as the long-term question of what ECMAScript can address next: we’ll be looking at all of those soon.

Group Created with Sketch.
TNS DAILY NEWSLETTER Receive a free roundup of the most recent TNS articles in your inbox each day.