stage-0 to stage-4 ECMAscript proposals.
TOC:
- Stage 0:
- Defensible Classes
- Relationships
- String.prototype.at
- Reflect.isCallable
- Reflect.isConstructor
- Additional metaproperties
- Function Bind Syntax
- Do Expressions
- 64-Bit Integer Operations
- Method Parameter Decorators
- Function Expression Decorators
- Zones
- Explicit syntactic opt-in for Tail Calls
- Object enumerables
- Nested import declarations
- Stage 1:
- Stage 2:
- Stage 3:
- Stage 4:
Stage-0
// const class
const class Point {
constructor(x, y) {
public getX() { return x; }
public getY() { return y; }
}
toString() {
return `<${this.getX()}, ${this.getY()}>`;
}
}
Stage-0
x @ r // The object x is in the r relationship with what value?
x @ r = y; // Store that x is in the r relationship with value y.
Stage-0
'abcπdef'.at(3)
// β 'π'
Stage-0
Reflect.isCallable(argument);
Stage-0
Reflect.isConstructor(argument)
Stage-0
function.callee; // function object that is currently being evaluated by the running execution context.
function.count; // number of arguments pass to the function.
function.arguments; // array containing the actual arguments passed to the function.
Stage-0
// :: which performs this binding and method extraction.
Promise.resolve(123).then(::console.log);
Stage-0
// do all the flexible things you can do with statements while still producing a useful result and plugging that back into an expression context.
x = do { let t = f(); t * t + 1 };
Stage-0
// return the high 32 bit part of the 64 bit addition of (hi0, lo0) and (hi1, lo1)
Math.iaddh(lo0, hi0, lo1, hi1);
// return the high 32 bit part of the 64 bit subtraction of (hi0, lo0) and (hi1, lo1)
Math.isubh(lo0, hi0, lo1, hi1);
// return the high 32 bit part of the signed 64 bit product of the 32 bit numbers a and b
Math.imulh(a, b);
// return the high 32 bit part of the unsigned 64 bit product of the 32 bit numbers a and b
Math.umulh(a, b);
Stage-0
//decorators that operate on method and constructor parameters.
class MyComponent {
refresh(@lastRefreshTime timeStamp) { β¦ }
}
export function lastRefreshTime(...) {
// at minimum, the arguments of this function should contain:
// - reference to owner of the parameter (the method)
// - parameter index
// - parameter name
// - is parameter a rest parameter?
// store parameter metadata using the same storage mechanism
// as the one used for methods
}
Stage-0
scheduleForFrequentReexecution(@memoize function(value) {
value++
});
export function memoize(...) {
// at minimum, the arguments of this function should contain:
// - reference to the decorated function expression
// - arguments passed into the memoize function (if any)
// wrap the decorated function expression memoization implementation and return it
}
Stage-0
//a primitive for context propagation across multiple logically-connected async operations
class Zone {
constructor({ name, parent });
name;
get parent();
fork({ name });
run(callback);
wrap(callback);
static get current();
}
const loadZone = Zone.current.fork({ name: "loading zone" });
window.onload = loadZone.wrap(e => { ... });
Stage-0
let factorial = (n, acc = 1) =>
n == 1 ? acc
: continue factorial(n - 1, acc * n);
Stage-0
Object.enumerableKeys(obj); // Ordered list of keys.
Object.enumerableValues(obj); // Ordered list of Values.
Object.enumerableEntries(obj); //Ordered list of key value pairs.
Stage-0
describe("fancy feature #5", () => {
import { strictEqual } from "assert";
it("should work on the client", () => {
import { check } from "./client.js";
strictEqual(check(), "client ok");
});
it("should work on the client", () => {
import { check } from "./server.js";
strictEqual(check(), "server ok");
});
it("should work on both client and server", () => {
import { check } from "./both.js";
strictEqual(check(), "both ok");
});
});
Stage-1
export * as ns from "mod"; // Exporting the ModuleNameSpace object as a named export.
Stage-1
export v, {x, y as w} from "mod";
export v, * as ns from "mod";
Stage-1
// Observable as a Constructor:
function listen(element, eventName) {
return new Observable(observer => {
// Create an event handler which sends data to the sink
let handler = event => observer.next(event);
// Attach the event handler
element.addEventListener(eventName, handler, true);
// Return a function which will cancel the event stream
return () => {
// Detach the event handler from the element
element.removeEventListener(eventName, handler, true);
};
});
}
// Observable.of creates an Observable of the values provided as arguments
Observable.of("R", "G", "B").subscribe({
next(color) {
console.log(color);
}
});
// Observable.from converts its argument to an Observable.
Observable.from(["R", "G", "B"]).subscribe({
next(color) {
console.log(color);
}
});
Stage-1
var str = 'Hello world!!!';
var regexp = /(\w+)\W*/g;
console.log(str.matchAll(regexp));
/*
[
{
0: "Hello ",
1: "Hello"
index: 0,
input: "Hello world!!!"
},
{
0: "world!!!",
1: "world"
index: 6,
input: "Hello world!!!"
}
]
*/
Stage-1
class Point {
#x = 0;
#y = 0;
constructor() {
this.#x; // 0
this.#y; // 0
}
}
Stage-1
// Make a new weak reference.
// The target is a strong pointer to the object that will be pointed
// at weakly by the result.
// The executor is an optional argument that will be invoked after the
// target becomes unreachable.
// The holdings is an optional argument that will be provided to the
// executor when it is invoked for target.
makeWeakRef(target, executor, holdings);
Stage-1
class Realm {
// From the prior Realm API proposal
const global -> object // access this realm's global object
eval(stringable) -> any // do an indirect eval in this realm
// We expect the rest of earlier proposal to be re-proposed eventually in
// some form, but do not rely here on any of the remainder.
// New with this proposal
static immutableRoot() -> Realm // transitively immutable realm
spawn(endowments) -> Realm // lightweight child realm
}
Stage-1
new Promise((resolve, reject, cancel) => { ... })
Promise.cancel(cancelation)
promise.then(onFulfilled, onRejected, onCanceled)
promise.cancelCatch(cancelation => { ... })
Stage-1
//returns a new ArrayBuffer whose contents are taken from oldBuffer
var buf1 = new ArrayBuffer(40);
new Int32Array(buf1)[0] = 42;
var buf2 = ArrayBuffer.transfer(buf1, 80);
assert(buf1.byteLength == 0);
assert(buf2.byteLength == 80);
assert(new Int32Array(buf2)[0] == 42);
var buf3 = ArrayBuffer.transfer(buf2, 0);
assert(buf2.byteLength == 0);
assert(buf3.byteLength == 0);
Stage-1
const regexGreekSymbol = /\p{Script=Greek}/u;
regexGreekSymbol.test('Ο');
Stage-1
// Possible ones:
Math.map
Math.scale
Math.remap
Math.clamp
Math.constrain
Math.toDegress(dobule, angrad)
Math.toRadians(double, arndeg)
Stage-2
// The proposal is about fixing those Illegal token errors, avoid restrictions on escape sequences.
let document = latex`
\newcommand{\fun}{\textbf{Fun!}} // works just fine
\newcommand{\unicode}{\textbf{Unicode!}} // Illegal token!
\newcommand{\xerxes}{\textbf{King!}} // Illegal token!
Breve over the h goes \u{h}ere // Illegal token!
Stage-2
// System.global to rule them all.
var getGlobal = function () {
// the only reliable means to get the global object is
// `Function('return this')()`
// However, this causes CSP violations in Chrome apps.
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');
};
Stage-2
var sab = new SharedArrayBuffer(1024); // 1KiB shared memory
w.postMessage(sab, [sab])
// In the worker:
var sab;
onmessage = function (ev) {
sab = ev.data; // 1KiB shared memory, the same memory as in the parent
}
Stage-2
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; // Rest.
let n = { x, y, ...z }; // Spread.
Stage-2
// Avoid ingnoring the first `next` call.
function *adder(total=0) {
let increment=1;
do {
switch (request = function.sent){
case undefined: break;
case "done": return total;
default: increment = Number(request);
}
yield total += increment;
} while (true)
}
let tally = adder();
tally.next(0.1); // argument no longer ignored
tally.next(0.1);
tally.next(0.1);
let last=tally.next("done");
console.log(last.value); //0.3
Stage-2
asyncIterator.next().then(result => console.log(result.value));
for await (let line of readLines(filePath)) {
print(line);
}
async function *readLines(path) {
let file = await fileOpen(path);
try {
while (!file.EOF)
yield file.readLine();
} finally {
await file.close();
}
}
Stage-2
// Class instance field
class MyClass {
myProp = 42;
constructor() {
console.log(this.myProp); // Prints '42'
}
}
// Static property
class MyClass {
static myStaticProp = 42;
constructor() {
console.log(MyClass.myStaticProp); // Prints '42'
}
}
Stage-2
Promise.resolve(2).finally(() => {})
Promise.reject(3).finally(() => {})
Stage-2
// Class Instance Fields
class ClassWithoutInits {
myProp;
}
class ClassWithInits {
myProp = 42;
}
// Class Static Properties
class MyClass {
static myStaticProp = 42;
constructor() {
console.log(MyClass.myStaticProp); // Prints '42'
}
}
Stage-2
String.prototype.trimLeft(" Meow"); // "Meow"
String.prototype.trimRight("Meow "); // "Meow"
Stage-2
class C {
@writable(false)
method() { }
}
function writable(value) {
return function (target, key, descriptor) {
descriptor.writable = value;
return descriptor;
}
}
Stage-3
// String's parse must contains the same
// function body and parameter list as the original.
O.gOPD({ get a(){} }, "a").get // "function a(){}"
O.gOPD({ set a(b){} }, "a").set // "function a(b){}"
Stage-3
/*a meta-variable ranging over all SIMD types:
Float32x4, Int32x4, Int16x8 Int8x16, Uint32x4,
Uint16x8, Uint8x16, Bool32x4, Bool16x8 and Bool8x16. */
Stage-3
function tag(strs) {
strs[0] === undefined
strs.raw[0] === "\\unicode and \\u{55}";
}
tag`\unicode and \u{55}`
let bad = `bad escape sequence: \unicode`; // throws early error
Stage-4
async function chainAnimationsAsync(elem, animations) {
let ret = null;
try {
for(const anim of animations) {
ret = await anim(elem);
}
} catch(e) { /* ignore and keep going */ }
return ret;
}
Stage-4
function foo(
param1,
param2,
) {}