- Interesting ECMAScript 2017 proposals that weren’t Adopted
- Originally written by Kaelan Cooter
- The Nuggets translation Project
- Permanent link to this article: github.com/xitu/gold-m…
- Translator: Colafornia
- Proofreader: Jasonxia23 Kezhenxu94
It’s not easy to keep up with all the new feature proposals. Each year, TC39, the committee that governs JavaScript development, receives dozens of proposals. Since most proposals don’t make it to the second stage, it’s hard to determine which ones are worthy of attention and which are just whimsical (or whimsical).
With more and more proposals coming out these days, it can be difficult to stay at the top of these feature proposals. In the past six years between ES5 and ES6, JavaScript has moved at a very conservative pace. Since the release of ECMAScript 2016 (ES7), the release process is required to be annual and more standardized.
With the popularity of polyfills and translators in recent years, early-stage proposals become widely used even before they are finalized. Also, because proposals can change significantly before they are adopted, some developers may find that features they use never become language implementations of JavaScript.
Before delving into proposals that I find fun, let’s take a moment to familiarize ourselves with the current proposal process.
The five stages in the ECMAScript proposal process
Stage 0 straw Man — This is the starting point for all proposals. The content of the proposal could change significantly before moving on to the next stage. There is currently no acceptance criteria for proposals and anyone can submit new proposals for this stage. No code implementation is required, and the specification does not have to conform to standards. The purpose of this phase is to start the discussion of the feature. There are currently more than 20 proposals in Stage 0.
Stage 1 “Proposal” — a real formal proposal. Proposals at this stage require a “champion” (i.e., a member of the TC39 Committee). At this stage, you need to carefully consider the API and describe any potential code implementation challenges. In this stage, polyfill needs to be developed and demo produced. Proposals may change significantly after this stage and should therefore be used with care. Proposals still at this stage include the much-anticipated Observables Type and promise.try functionality.
Stage 2 “draft” — This Stage will use the formal TC39 specification language to describe the exact syntax. Minor changes may still occur after this stage, but the specification should be complete enough to avoid major revisions. If a proposal goes this far, it is likely that the committee wants to implement this feature eventually.
Stage 3 “candidate” — This proposal has been approved and further changes will only be made if requested by the executive author. At this point you can expect the proposal functionality to start being implemented in the JavaScript engine. At this stage the draft polyfill can be used safely and without worry.
Stage 4 “Done” — indicates that the proposal has been adopted and that the proposal specification will be merged with the JavaScript specification. No further changes are expected. JavaScript engines publish their implementations. As of October 2017, there are nine completed proposals, the most notable of which is Async Functions.
As more and more proposals come to mind, here are some of the more interesting ones.
Figure source xkcd.com/927/
Asynchronous Iteration Asynchronous Iteration
ECMAScript 2015 introduced the iterator iterator, which includes for-of syntax. This makes it fairly easy to loop through the iterable and implement your own iterable data structures.
Unfortunately, traversers cannot be used to represent asynchronous data structures such as access file systems. While you can run promise.all to iterate through a series of promises, this requires simultaneous determination of the “completed” state.
For example, asynchronous iterators can be used to iterate over asynchronous content, reading the contents of a file on demand rather than reading everything in the file ahead of time.
You can define asynchronous generator functions simply by using both generator and async-await syntax:
async function* readLines(path) {
let file = await fileOpen(path);
try {
while(! file.EOF) {yield awaitfile.readLine(); }}finally {
awaitfile.close(); }}Copy the code
Example asynchronous generator function.
The sample
We can use this asynchronous generator in a for-await-of loop:
for await (const line of readLines(filePath)) {
console.log(line);
}
Copy the code
Use the for – await -.
Any object that has the Symbol. AsyncIterator property is defined as async iterable and can be used in the new for-await-of syntax. Here is a concrete working example:
class LineReader(a){
constructor(filepath) {
this.filepath = filepath;
this.file = fileOpen(filepath);
}
[Symbol.asyncIterator]: {
next() {
return new Promise((resolve, reject) = > {
if (this.file.EOF) {
resolve({ value: null.done: true });
} else {
this.file.readLine()
.then(value= > resolve({ value, done: false }))
.catch(error= >reject(error)); }}); }}}Copy the code
An example using symbol.asynciterator.
This proposal is currently in stage 3 and is already being implemented in browsers. Being at this stage means it is likely to be incorporated into the standard and available in major browsers. However, there may be some minor changes to the specification before then, so using asynchronous iterators now carries a degree of risk.
The ReGenerator project now provides basic support for asynchronous iterator proposals. However, it does not support for-await-of loop syntax per se. The Babel plugin transform-async-generator-functions supports both asynchronous generators and for-await-of loop syntax.
The Class optimization
The proposal to introduce the class of grammar] in [ECMAScript 2015 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) Add public fields, private fields, and private methods to the The proposal was the result of lengthy discussions and competition among several competing proposals.
Using private fields and methods is similar to the corresponding public fields and methods, except that the private field name is preceded by a #. Any methods and fields that are marked private are not visible outside the class, ensuring strong encapsulation of the inner class members.
Here is a hypothetical example of a React class component that uses public and private fields in private methods:
Class Counter {// public field text = 'Counter'; #state = {count: 0,}; // Private method #handleClick() {this.#state.count++; Render () {return (<button onClick={this.handleclick.bind (this)}> {this.text}: {this.#state.count.toString()} </button> ); }}Copy the code
React component that uses private fields and private methods.
Babel does not yet provide polyfills for private class fields and methods, but will soon. Public fields are already supported by Babel’s transform-class-properties plug-in, but it relies on an old proposal that has been incorporated into the uniform public/private field proposal. This proposal entered Stage 3 on September 1, 2017, so it is safe to use any polyfill available.
The Class decorator
Proposals can change dramatically once they are introduced, and decorators are a good example. The fifth version of Babel implements the original Stage 2 decorator specification, which defines decorators as functions that receive descriptions of target, name, and attributes. The most popular way to translate decorators today is through Babel’s transform-legacy-decorators plug-in, which implements older versions of the specification.
The new proposal is quite different. Instead of being a function with three attributes, we now have a formal description of the decorator, the class member that changes the descriptor. The new “member descriptor” is very similar to the attribute descriptor interface introduced in ES5.
There are now two different types of decorators with different apis: member decorators and class decorators.
- The member decorator receives the member descriptor and returns the member descriptor.
- The class decorator accepts an array of constructors, parent classes, and member descriptors for each class member (that is, each property or method).
In the specification, “extra” means an optional array of member descriptors that can be added by decorators. This allows the decorator to dynamically create new properties and methods. For example, you can have a decorator create getters and setters for properties.
Like the old specification, the new specification allows you to modify the descriptors of class members. In addition, the use of decorators on properties of object literals is still allowed.
The specification is likely to change significantly before it is finalized. There are ambiguities in the syntax, and many pain points from the old specification have not been addressed. Decorators are a large syntactic extension of the language, so you can expect this delay. Unfortunately, if the new proposal is adopted, you will have to completely refactor your decorator functions to fit the new interface.
Many library authors choose to continue supporting the old proposal and Babel’s legacy-Decorators plug-in, even though the new proposal is on Stage 2 and the old one is still on Stage 0. Core-decorators, the most popular JavaScript open source library that uses decorators, takes this approach. It is likely that library’s authors will continue to support the old proposals for years to come.
It is also possible that this new proposal will be withdrawn and replaced by another one, and that the decorator proposal may not incorporate JavaScript in 2018. You can use the new decorator proposal after Babel completes the new translation plug-in.
The import function
ECMAScript version 6 added import statements and finalized the semantics of the new module system. Just recently, major browsers released updates to provide support for it, although they implement the specification slightly differently. NodeJS provides initial support for the still-experimental ECMAScript module specification in version 8.5.0.
However, the proposal lacks a way to import modules asynchronously, making it difficult to import modules dynamically at run time. Now, the only way to dynamically load a module in a browser is to dynamically insert a script tag of type “module” with the import declaration as its text content.
One built-in way to implement asynchronous import modules is the proposal dynamic import syntax, which calls a “class function” of the import module to load the form. This dynamic import syntax can be used in both module code and plain script code, providing a convenient entry point for module code.
Last year there was a proposal for the system.import () function to solve this problem, but it was not adopted into the final specification. The new proposal is currently in stage 3 and is expected to be included in the specification by the end of the year.
Observables
The proposed Observable Type, Observable Type, provides a standardized way to handle asynchronous data flows. They are already implemented in some form in many popular JavaScript frameworks such as RxJS. The current proposal draws heavily on the ideas of these frameworks.
Observable objects are created by the Observable constructor and take a subscription function as an argument:
function listen(element, eventName) {
return new Observable(observer= > {
// Create an event handler that outputs data
let handler = event= > observer.next(event);
// Bind event handlers
element.addEventListener(eventName, handler, true);
// Returns a function called to unsubscribe
return (a)= > {
// Remove event listening for the element
element.removeEventListener(eventName, handler, true);
};
});
}
Copy the code
Observable constructor usage.
Subscribe to an Observable using the subscribe function:
constSubscription = listen(inputElement, "keydown").subscribe({next(val) {console.log("Got key: " + val) },
error(err) { console.log("Got an error: " + err) },
complete() { console.log("Stream complete!")}});Copy the code
Use the Observable object.
The subscribe() function returns a subscription object. This object has methods to unsubscribe.
Observable should not be confused with the deprecated object. observe function, which is a way to observe Object changes. It has been replaced by a more generic implementation Proxy in ECMAScript 2015.
Observable is currently in stage 1, but it is expected to move to the next phase soon as it has been labeled “ready to advance” by the TC39 committee and has strong support from browser vendors. You are now ready to use the features of this proposal, with three polyfill implementations to choose from.
Do expression
CoffeeScript was once best known for being an everything-for-everything expression, and although its popularity has waned, it has had a major impact on the recent development of JavaScript.
The DO expression presents a new syntax for wrapping multiple statements in a single expression. Code can be written as follows:
let activeToDos = do {
let result;
try {
result = fetch('/todos');
} catch (error) {
result = []
}
result.filter(item= > item.active);
}
Copy the code
Example do expression.
The last statement of the DO expression is implicitly returned as the completion value.
Do expressions are very useful in JSX. Unlike complex ternary expressions, DO expressions can make process control in JSX more readable.
const FooComponent = ({ kind }) = > (
<div>
{do {
if (kind === 'bar') { <BarComponent /> }
else if (kind === 'baz') { <BazComponent /> }
else { <OtherComponent />}}}</div>
)
Copy the code
The future of JSX?
Babel already has plug-ins to translate DO expressions. This proposal is currently in Stage 1 and there are some important open questions about how to use it with Generator and Async functions, so the specification is likely to change significantly.
Optional Chaining is invoked for chains of empty (Optional) attributes
Another proposal, inspired by CoffeeScript, is Optional Chaining, which brings an easy way to access object attributes without the need for lengthy ternary operators for attributes that may be undefined or null. It is similar to the CoffeeScript existence operator, but lacks some notable features, such as range checking and optional assignment.
Example:
a? .b// if 'a' is null/undefined, undefined; otherwise, the value of 'a.b' is returned
a == null ? undefined : a.b // Use ternary expressions
Copy the code
The proposal is currently in stage 1 and is already implemented by a Babel plug-in named babel-plugin-transform-optional-chaining. The TC39 committee raised concerns about its grammar at its last meeting in October 2017, but it may yet be adopted.
Global object standardization
Writing JavaScript code that runs in every environment is not easy. In a browser, the global object is a window — except in a Web worker, where the global object is itself. In NodeJS it is global, but this is an addition to the V8 engine and is not part of the specification, so the global object is not available when running code directly in V8.
The proposal to standardize presents global objects that can be used in all engines and runtime environments. The proposal is currently in stage 3, so it will be adopted soon.
And more
The TC39 Committee is considering more than fifty active proposals, which do not include the twenty or so proposals at Stage 0 that have not yet been advanced.
You can check out the list of active proposals on TC39’s GitHub page. Some of the more sketchy ideas can be found in the Stage 0 proposal module, including things like method parameter decorators and new pattern-matching syntax.
The Committee’s priorities and current issues can also be learned in the Minutes and agenda warehouse. The lecture materials are also displayed in the proceedings, and you can check them out if you are interested in them.
There have been several significant proposed syntax changes in recent ECMAScript revisions, and this seems to be part of the trend. ECMAScript is accelerating the pace of change, with more and more proposals being made each year, and it seems likely that the 2018 version will adopt more proposals than the 2017 version.
This year, there were smaller proposals to add “quality of life” improvements to the language, such as type checking for built-in objects and degree and radian assistant proposals to the Math module. Such proposals will be added to the standard library rather than changing the syntax. They are easy to polyfill and help reduce the need for third-party libraries. Since you don’t have to change the syntax, it’s quick to use and takes less time in the proposal phase.
The new syntax is great, but I’d love to see more of this type of proposal in the future. JavaScript is often criticized for lacking a good standard library, but efforts are clearly being made to change that.
Plug in: LogRocket, Web application DVR
LogRocket is a front-end logging tool that lets you replay problems as if they were in your browser. Instead of guessing why an error occurred or asking the user for screenshots and log uploads, LogRocket allows replay sessions to quickly locate the source of the error. No matter what framework is used, LogRocket can be used in any application and has plug-ins to record context from Redux, Vuex and @ngrx/ Store.
In addition to logging Redux actions and states, LogRocket can log console logs, JavaScript errors, call stack information, network requests, response headers, and entity information, browser meta-information, and custom logs. It also uses DOM to record HTML and CSS on a page, allowing even the most complex single-page applications to redraw pixel-perfect videos.
The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.