Skip to content

Instantly share code, notes, and snippets.

@hemanth
Created April 17, 2019 09:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hemanth/51578482ab61b51e0d3c067350d9f514 to your computer and use it in GitHub Desktop.
Save hemanth/51578482ab61b51e0d3c067350d9f514 to your computer and use it in GitHub Desktop.
Stage0-Stage4

[fit] Did you know?



#[fit] STAGE 0

`as` destructuring patterns
Kat Marchán
const {x: {y} as x} = {x: {y: 1}}
// x is {y: 1}
// y is 1

function foo ([{y} as x, [z] as zed = [1]]) {
  // x is {y: ...}
  // y is x.y
  // z is runs an initializer if arguments[0][1] is undefined
}

Symbol.thenable
Gus Caplan
Promise.resolve({
  [Symbol.thenable]: false,
  then() { return 'a time that isn\'t now'; },
}).then((o) => {
  o.then() === 'a time that isn\'t now';
});

deprecated directive
James M Snell	
function deprecatedFunction() {
  deprecated;
  // do stuff
}

// or 

function deprecatedFunction() {
  'deprecated';
  // do stuff
}


function deprecatedFunction() {
  'deprecated; This is deprecated, use something else';
  // do stuff
}

Decimal	
Andrew Paprocki
Daniel Ehrenberg
// Number (binary 64-bit floating point)
js> 0.1 + 0.2
=> 0.30000000000000004

// Decimal (???)
js> 0.1m + 0.2m
=> 0.3m
  • Rationals
  • Fixed size decimals
  • Seralization

Object Shorthand Improvements
Ron Buckton
const a = { o["x"] };

// ^ const a = { ["x"]: o["x"] };
const a = { o.x };

({ a.x } = o);

({ ["x"]: a["x"] } = o);

class Zone {
  constructor({ name, parent });

  name;
  get parent();

  fork({ name });
  run(callback);
  wrap(callback);

  static get current();
}
window.onload = Zone.current.wrap(e => {
  // (1)

  fetch("https://example.com").then(Zone.current.wrap(res => {
    // (2)

    return processBody(res.body).then(Zone.current.wrap(data => {
      // (5)

      const dialog = html`<dialog>Here's some cool data: ${data}
                          <button>OK, cool</button></dialog>`;
      dialog.show();

      dialog.querySelector("button").onclick = Zone.current.wrap(() => {
        // (6)
        dialog.close();
      });
    }));
  }));
});

function processBody(body) {
  // (3)
  return body.json().then(Zone.current.wrap(obj => {
    // (4)
    return obj.data;
  }));
}

WHATWG URL
James M Snell	
const site = new url.URL('https://h3manth.com');

const url = url.URL('bar', site);

/*
URL {
  href: 'https://h3manth.com/bar',
  origin: 'https://h3manth.com',
  protocol: 'https:',
  username: '',
  password: '',
  host: 'h3manth.com',
  hostname: 'h3manth.com',
  port: '',
  pathname: '/bar',
  search: '',
  searchParams: URLSearchParams {},
  hash: '' }
  */

String.prototype.at
Mathias Bynens	
assertEquals('\uD834abc'.at(-Infinity), '');
assertEquals('\uD834abc'.at(-1), '');
assertEquals('\uD834abc'.at(-0), '\uD834');
assertEquals('\uD834abc'.at(+0), '\uD834');
assertEquals('\uD834abc'.at(1), 'a');
assertEquals('\uD834abc'.at(42), '');
assertEquals('\uD834abc'.at(+Infinity), '');
assertEquals('\uD834abc'.at(null), '\uD834');
assertEquals('\uD834abc'.at(undefined), '\uD834');
assertEquals('\uD834abc'.at(), '\uD834');
assertEquals('\uD834abc'.at(false), '\uD834');
assertEquals('\uD834abc'.at(NaN), '\uD834');
assertEquals('\uD834abc'.at(''), '\uD834');
assertEquals('\uD834abc'.at('_'), '\uD834');
assertEquals('\uD834abc'.at('1'), 'a');

Relationships
Mark Miller & Waldemar Horwat
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.

Reflect.{isCallable,isConstructor}
Caitlin Potter	
Reflect.isCallable(argument);
Reflect.isConstructor(argument)

Orthogonal Class Member Syntax
Mark S. Miller and Allen Wirfs-Brock
//A kitchen sink example
class Foo {
  //instance members
  own x=0, y=0;  // two data properties
  own #secret;   // a private field
                 // initial value undefined
  own *[Symbol.iterator](){yield this.#secret}
                 // a generator method
  own #callback(){}  //a private instance method  
  //class constructor members               
  static #p=new Set(), q=Foo.#p;
                // a private field and a property
                // of the class constructor                     
  static get p(){return Foo.#p} //accessor method     
  //prototype methods                
  setCallback(f){this.#callback=f}
  constructor(s){
     this.#secret = s;
  }
}

Nested `import` declarations
Ben Newman 
import { strictEqual } from "assert";
import { check as checkClient } from "./client.js";
import { check as checkServer } from "./server.js";
import { check as checkBoth } from "./both.js";
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 server", () => {
    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");
  });
});

Method parameter decorators	
Igor Minar	
//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
}

Function expression decorators
Igor Minar	
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
}

Function bind syntax
Kevin Smith	
import { map, takeWhile, forEach } from "iterlib";

getPlayers()
::map(x => x.character())
::takeWhile(x => x.strength > 100)
::forEach(x => console.log(x));
$(".some-link").on("click", ::view.reset);
// Create bindings for just the methods that we need
let { find, html } = jake;

// Find all the divs with class="myClass", then get all of the "p"s and
// replace their content.
document.querySelectorAll("div.myClass")::find("p")::html("hahaha");

evalable	
Mike Samuel	
console.log(eval(123) === 123);

const array = [ 'alert(1)' ];
console.log(eval(array) === array);  // Does not alert

const touchy = { toString() { throw new Error(); } };
console.log(eval(touchy) === touchy);  // Does not throw.
$ npx node@10 --disallow_code_generation_from_strings -e 'console.log(eval(() => {}))'
[Function]

$ npx node@10 --disallow_code_generation_from_strings -e 'console.log(eval("() => {}"))'
[eval]:1
console.log(eval("() => {}"))
        ^

EvalError: Code generation from strings disallowed for this context

Defensible Classes	
Mark Miller & Doug Crockford	
/*
 * constructor function and 
 * prototype object are frozen and 
 * the variable the class is bound to is const 
*/ 

const class Point { 
  constructor(x, y) {
    public getX() { return x; }
    public getY() { return y; }
  }
  toString() { 
    return '<' + this.getX() + ',' + this.getY() + '>';
  }
}
  trait ColorTrait {
    new(col) {
      public color() { return col; }
    }
  }
  class ColoredPoint {
    mixin ColorTrait;
    new(col) {
      mixin ColorTrait(col);
    }
  }

Array.isTemplateObject
Mike Samuel	
function (trustedStrings, ...untrustedArguments) {
  if (!Array.isTemplateObject(trustedStrings)) {
    // Do not trust trustedStrings
  }
  // Proceed knowing that trustedStrings
}

Additional metaproperties
Allen Wirfs-Brock	
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.

[fit] STAGE 1


export v from "mod"; statements
Ben Newman + John-David Dalton
export v, {x, y as w} from "mod";

export v, * as ns from "mod";

Observable 
Jafar Husain + Mark Miller
// 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);
    }
});

Frozen Realms 
Mark Miller + Chip Morningstar + Caridy Patiño
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
}

Math Extensions 
Rick Waldron
// Possible ones:
Math.map
Math.scale
Math.remap
Math.clamp
Math.constrain
Math.toDegrees(double angrad)
Math.toRadians(double angdeg)

of and from on collection constructors 
Leo Balter + Allen Wirfs-Brock
Map.of ( ...items )
Set.of ( ...items )
WeakMap.of ( ...items )
WeakSet.of ( ...items )
Map.from ( source [ , mapFn [ , thisArg ] ] )
Set.from ( source [ , mapFn [ , thisArg ] ] )
WeakMap.from ( source [ , mapFn [ , thisArg ] ] )
WeakSet.from ( source [ , mapFn [ , thisArg ] ] )

Promise.try 
Jordan Harband
function getUserById(id) {
    return Promise.try(function() {
        if (typeof id !== "number") {
            throw new Error("id must be a number");
        }
        return db.getUserById(id);
    });
}

Optional Chaining 
Gabriel Isenberg + Dustin Savery
obj?.prop       // optional static property access
obj?.[expr]     // optional dynamic property access
func?.(...args) // optional function or method call
delete a?.b
// delete (a == null ? undefined : a.b) // that *would* work if `? :` could return a Reference...
a == null ? undefined : delete a.b      // this is what we get, really
a?.b.c(++x).d  // if `a` is null/undefined, evaluates to undefined. Variable `x` is not incremented.
               // otherwise, evaluates to `a.b.c(++x).d`.
a == null ? undefined : a.b.c(++x).d
a?.b[3].c?.(x).d
a == null ? undefined : a.b[3].c == null ? undefined : a.b[3].c(x).d
  // (as always, except that `a` and `a.b[3].c` are evaluated only once)

Math.signbit: IEEE-754 sign bit 
JF Bastien
Math.signbit(x);

/*
Returns whether the sign bit of x is set.

If n is NaN, the result is false.
If n is -0, the result is true.
If n is negative, the result is true.
Otherwise, the result is false.
*/

Error stacks 
Jordan Harband
Error.prototype.stack;
System.getStack;
System.getStackString;


Object.getOwnPropertyDescriptor(new Error(), 'stack');
Object.getOwnPropertyDescriptor(Error.prototype, 'stack');

do expressions 
Dave Herman
let x = do {
  let tmp = f();
  tmp * tmp + 1
};
let x = do {
  if (foo()) { f() }
  else if (bar()) { g() }
  else { h() }
};

Float16 on TypedArrays, DataView, Math.hfround 
Leo Balter
let float16 = new Float16Array([1.0, 1.1, 1.2]);
for(const val of float16) {
    console.log(val); // => 1, 1.099609375, 1.19921875
}
 
float16.reduce((prev, current) => prev + current); // 3.298828125
let buffer = new ArrayBuffer(10);
let view = new DataView(buffer);
 
view.setUint16(0, 0x1234);
getFloat16(view, 0); // 0.0007572174072265625
 
// You can append to DataView instance
view.getFloat16 = getFloat16.bind(null, view);
view.setFloat16 = setFloat16.bind(null, view);
 
view.getFloat16(0); // 0.0007572174072265625
 
view.setFloat16(0, Math.PI, true);
view.getFloat16(0, true); // 3.140625

The Pipeline Operator
Daniel Ehrenberg
let result = exclaim(capitalize(doubleSay("hello")));
result //=> "Hello, hello!"

let result = "hello"
  |> doubleSay
  |> capitalize
  |> exclaim;

result //=> "Hello, hello!"

Extensible numeric literals 
Daniel Ehrenberg
decorator @px {
  @numericTemplate(({ number }) => CSS.px(number))
}

3@px;

// de-sugars into

let template = Object.freeze({ number: 3, string: "3" });
(() => ({ number }) => CSS.px(number))()(template);

First-class protocols 
Michael Ficarra
protocol ToString {
  tag;

  toString() {
    return `[object ${this[ToString.tag]}]`;
  }
}

Object.prototype[ToString.tag] = 'Object';
Protocol.implement(Object, ToString);

Nullish coalescing Operator 
Gabriel Isenberg
const response = {
  settings: {
    nullValue: null,
    height: 400,
    animationDuration: 0,
    headerText: '',
    showSplashScreen: false
  }
};

const undefinedValue = response.settings?.undefinedValue || 'some other default'; // result: 'some other default'
const nullValue = response.settings?.nullValue || 'some other default'; // result: 'some other default'

Partial application 
Ron Buckton
const addOne = add(1, ?); // apply from the left
addOne(2); // 3

const addTen = add(?, 10); // apply from the right
addTen(2); // 12

// with pipeline
let newScore = player.score
  |> add(7, ?)
  |> clamp(0, 100, ?); // shallow stack, the pipe to `clamp` is the same frame as the pipe to `add`.

// partial template strings
const Diagnostics = {
  unexpected_token: `Unexpected token: ${?}`,
  name_not_found: `'${?}' not found.`
};
Diagnostics.name_not_found("foo"); // "'foo' not found."

Cancellation API 
Ron Buckton Brian Terlson
function fetchConsumer(url) {
  const source = new CancellationTokenSource();
  setTimeout(() => source.cancel(), 1000); // cancel after 1sec.
  return fetchAsync(url, source.token);
}
async function startMonitoring(timeoutSource, disconnectSource) {
  const monitorSource = new CancellationTokenSource([timeoutSource, disconnectSource]);
  while (!monitorSource.cancellationRequested) {
    await pingUser();
  }
}

String.prototype.codePoints 
Mathias Bynens
function isIdent(input) {
    let codePoints = input.codePoints();
    let first = codePoints.next();

    if (first.done || !isIdentifierStart(first.value.codePoint)) {
        return false;
    }

    for (let { codePoint } of codePoints) {
        if (!isIdentifierContinue(codePoint)) {
            return false;
        }
    }

    return true;
}

Object.freeze + Object.seal syntax 
Keith Cirkel
> const x = Object.freeze({});
undefined
> x.foo
undefined
> Object.prototype.foo = 3;
3
> x.foo
3
const x = Object.freeze({ __proto__: null });
// Freeze
const foo = {#a: {#b: {#e: [# "some string!" #]} #} #}
// Seal.
const foo = {|a: {| b: {|e: [| "some string!" |]} |} |}

Block Params
Sam Goto
// ... this is what you write ...
a(1) {
  // ...
}

// ... this is what you get ...
a(1, () => {
  // ...
})
// ... this is what you write ...
a {
  // ...
}

// ... this is what you get ...
a(() => {
  // ...
})

{BigInt,Number}.fromString
Mathias Bynens
Number.fromString('42');
// → 42
Number.fromString('42', 10);
// → 42

BigInt.fromString('42');
// → 42n
BigInt.fromString('42', 10);
// → 42n

Math.seededRandoms() 
Tab Atkins
for(const [i,r] of enumerate(Math.seededPRNG({seed:0}))) {
  // do something with each value
  if(i >= limit) break;
}

Maximally minimal mixins 
Justin Fagnani
mixin M {
  method() {}
}

class A extends Object with M {}
class B extends Object with M {}

A.prototype.method === B.prototype.method; // false
class C extends A with M1, M2, M3 {}

Getting last item from Array
Keith Cirkel
myArray[myArray.length] // oops, index out of bounds, return `undefined`, scratch head for hours from silly mistake


myIndex = myArray.length - 1
myArray[myIndex - 1] // oops, overcooked index, returns last-but-one not last, scratch head for hours from silly mistake
Array.prototype.lastItem
Array.prototype.lastIndex

Collection methods 
Sathya Gunasekaran
require('core-js/proposals/collection-methods');

const colors = new Map([['red', '#FF0000'], ['gold', '#FFD700']]);
colors
  .mapKeys((value, key) => key.toUpperCase()) // Map { 'RED' => '#FF0000', 'GOLD' => '#FFD700' }
  .mapValues(value => value.toLowerCase()); // Map { 'RED' => '#ff0000', 'GOLD' => '#ffd700' }

Slice notation 
Sathya Gunasekaran
const obj = { 0: 'a', 1: 'b', 2: 'c', 3: 'd', length: 4 };
obj[1:3];
// → ['b', 'c']
const arr = ['a', 'b', 'c', 'd'];
arr[1:4:2];
// → ['b', 'd']

Logical Assignment Operators 
Justin Ridgewell
// "Or Or Equals" (or, the Mallet operator :wink:)
a ||= b;
a || (a = b);

// "And And Equals"
a &&= b;
a && (a = b);

// Eventually....
// "QQ Equals"
a ??= b;
a ?? (a = b);

Class Static Block 
Ron Buckton
// without static blocks:
class C {
  static x = ...;
  static y;
}

try {
  C.y = doSomethingWith(C.x);
}
catch {
  C.y = ...;
}

// with static blocks:
class C {
  static x = ...;
  static y;
  static {
    try {
      this.y = doSomethingWith(this.x);
    }
    catch {
      this.y = ...;
    }
  }
}

class Access Expressions 
Ron Buckton
// from a non-static method
class C {
  static f() { }
  g() {
    class.f();
    class["f"]();
  }
}

// from a static method
class C {
  static f() { }
  static g() {
    class.f();
    class["f"]();
  }
}

// with static private members
class C {
  static #f() {}
  static g() {
    class.#f();
  }
}

Pattern Matching 
Kat Marchán + Brian Terlson + Sebastian Markbåge
const res = await fetch(jsonService)
case (res) {
  when {status: 200, headers: {'Content-Length': s}} -> {
    console.log(`size is ${s}`)
  }
  when {status: 404} -> {
    console.log('JSON not found')
  }
  when {status} if (status >= 400) -> {
    throw new RequestError(res)
  }
}

Explicit Resource Management 
Ron Buckton
function * g() {
  using (const handle = acquireFileHandle()) { // critical resource
    ...
  } // cleanup
}

using (const obj = g()) {
  const r = obj.next();
  ...
} // calls finally blocks in `g`

Dynamic Modules 
Bradley Farias
export * from 'dynamic-module';
import { dynamicMethod } from './lib.js';
import * as lib from './lib.js';

JavaScript Standard Library
Michael Saboff + Mattijs Hoitink
import { ... } from std.SomeStandardModule;
import { ... } from <SomeStandardModule>;

include { ... } from <SomeStandardModule>;
include { ... } from "SomeStandardModule";

import { ... } from "https://www.ecma-international.com/ecmascript/SomeStandardModule";

import { ... } from "@std/SomeStandardModule";

JSON.parse source text access
Richard Gibson
const input = '\n\t"use\\u0020strict"';
let spied;
const parsed = JSON.parse(input, (key, val, src, pos, str) => (spied = {src, pos, str}, val));
parsed === 'use strict';
// → true
spied.src === '"use\\u0020strict"';
// → true
spied.pos === 2;
// → true
spied.str === input;
// → true

Asset References
Sebastian Markbage
asset Logo from "./logo.gif";
async function loadLogo() {
  let img = document.createElement("img");
  img.src = URL.createObjectURL(Logo);
  return img;
}

Freezing prototypes 
Kevin Gibbons
Object.freezePrototypeOf
Reflect.freezePrototypeOf
Object.isPrototypeOfFrozen
?

new.initialize()
Daniel Ehrenberg
// Avoiding super.
class D {
  #w = 2;
  get w() { return this.#w; }
  constructor() {
    const instance = Reflect.construct(C, [], new.target);
    new.initialize(instance);
    return instance;
  }
}

D.__proto__ = class {};
const broken = new D();
console.log(broken.v);  // 1!
console.log(broken.w);  // 2

Iterator Helpers
Gus Caplan
class ObligatoryCryptocurrencyReference extends Component {
  componentWillMount() {
    const items = ticker() // returns async iterator
      .map((c) => createElement('h2', null, `${c.name}: ${c.price}`))
      .take(5) // only consume 5 items of a potentially infinite iterator
      .collect() // greedily transform async iterator into array
      .then((data) => this.setState({ data }));
  }

  render() {
    return createElement('div', null, this.state.data);
  }
}
Promise.any
Mathias Bynens
try {
  const first = await Promise.any(promises);
  // Any of the promises was fulfilled.
} catch (error) {
  // All of the promises were rejected.
}
Promise.any(promises).then(
  (first) => {
    // Any of the promises was fulfilled.
  },
  (error) => {
    // All of the promises were rejected.
  }
);
Private declarations
Justin Ridgewell	
private #hello;
class Example {
  [#hello] = 'world!';
}

const ex = new Example();
console.log(ex.#hello);
// => 'world!'

[fit] STAGE 2


function.sent metaproperty 

Allen Wirfs-Brock
// 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

Decorators 
Yehuda Katz + Brian Terlson + Daniel Ehrenberg
@wrap, @register, @expose, @initialize
export decorator @logged {
  @wrap(f => {
    const name = f.name;
    function wrapped(...args) {
      console.log(`starting ${name} with arguments ${args.join(", ")}`);
      f.call(this, ...args);
      console.log(`ending ${name}`);
    }
    wrapped.name = name;
    return wrapped;
  })
}
import { @logged } from "./logged.mjs";

class C {
  @logged
  method(arg) {
    this.#x = arg;
  }

  @logged
  set #x(value) { }
}

new C().method(1);
// starting method with arguments 1
// starting set #x with arguments 1
// ending set #x
// ending method

throw expressions
Ron Buckton
function save(filename = throw new TypeError("Argument required")) {
}
lint(ast, { 
  with: () => throw new Error("avoid using 'with' statements.")
});
class Product {
  get id() { return this._id; }
  set id(value) { this._id = value || throw new Error("Invalid value"); }
}

Atomics.waitAsync 
Shu-yu + GuoLars Hansen
function test1() {
    Atomics.waitAsync(ia, 37, 0x1337, 1000)
    .then(function (r) { 
        log("Resolved: " + r); test2(); 
    });
}

WeakRefs 
Dean Tribble
// 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);

Top-level await 
Myles Borins
// awaiting.mjs
import { process } from "./some-module.mjs";
let output;
async function main() {
  const dynamic = await import(computedModuleSpecifier);
  const data = await fetch(url);
  output = process(dynamic.default, data);
}
main();
export { output };
const strings = await import(`/i18n/${navigator.language}`);

Function implementation hiding 
Domenic Denicola + Michael Ficarra
function foo() {
  const x = () => {};

  const y = () => {
    "hide implementation";
    class Z {
      m() {}
    }
  };
}

// In this example, foo and x remain unhidden, while y, Z, and Z.prototype.m are considered hidden.


New Set methods 
Sathya Gunasekaran
Set.prototype.intersection(iterable) - method creates new Set instance by set intersection operation.
Set.prototype.union(iterable) - method creates new Set instance by set union operation.
Set.prototype.difference(iterable) - method creates new Set without elements present in iterable.
Set.prototype.symmetricDifference(iterable) - returns Set of elements found only in either this or in iterable.
Set.prototype.isSubsetOf(iterable)
Set.prototype.isDisjointFrom(iterable)
Set.prototype.isSupersetOf(iterable)

Realms 
Dave Herman+ Mark Miller + Caridy Patiño
let realm = new Realm();

let outerGlobal = window;
let innerGlobal = realm.global;

let f = realm.evalScript("(function() { return 17 })");

f() === 17 // true

Reflect.getPrototypeOf(f) === outerGlobal.Function.prototype // false
Reflect.getPrototypeOf(f) === innerGlobal.Function.prototype // true


class EmptyRealm extends Realm {
  constructor(...args) { super(...args); }
  init() { /* do nothing */ }
}


class FakeWindow extends Realm {
  init() {
    super.init(); // install the standard primordials
    let global = this.global;

    global.document = new FakeDocument(...);
    global.alert = new Proxy(fakeAlert, { ... });
    ...
  }
}

ArrayBuffer.prototype.transfer()
Domenic Denicola
function validateAndWriteSafeAndFast(arrayBuffer) {
  // Transfer first!
  const transferred = arrayBuffer.transfer();

  await validate(transferred);
  await fs.writeFile("data.bin", transferred);
}

RegExp Match array offsets
Ron Buckton
const re1 = /a*(?<Z>z)?/;

// offsets are relative to start of the match:
const s1 = "xaaaz";
const m1 = re1.exec(s1, (start, end) => [start, end]);
m1[0][0] === 1;
m1[0][1] === 5;
s1.slice(...m1[0]) === "aaaz";
// the following two statements are functionally equivalent:
re1.exec(text);
re1.exec(text, (start, end, input) => input.slice(start, end));

Sequence properties in Unicode property escapes
Mathias Bynens
const regexEmojiKeycap = /\p{Emoji_Keycap_Sequence}/u;
regexEmojiKeycap.test('4️⃣');
// → true
const reRgiEmojiSequence = /\p{Emoji_Flag_Sequence}|\p{Emoji_Tag_Sequence}|\p{Emoji_ZWJ_Sequence}/u;

Temporal Maggie 
PintPhilipp Dunkel + Brian Terlson
// Temporal
let dateTimeAnywhere = new CivilDateTime(2000, 12, 31, 23, 59)
let instantInChicago = dateTimeAnywhere.withZone('America/Chicago');
let instantInSydney = new ZonedDateTime(instantInChicago.instant, 'Australia/Sydney')
let calendarClockDateTimeFromSydney = instantInSydney.toCivilDateTime()
dateTimeAnywhere.toString() // 2000-12-31T23:59:00.000000000
calendarClockDateTimeFromSydney.toString()  // 2001-01-01T16:59:00.000000000

collection normalization
Bradley Farias
new Map(undefined, {
  toKey({email}) {
    return email;
  },
  toValue(state) {
    return state instanceof AccountState ? 
      state :
      new AccountState(state);
  }
});
new Set(undefined, {
  toValue({username}) {
    return username;
  }
});

String.prototype.replaceAll 
Mathias Bynens
const queryString = 'q=query+string+parameters';
const withSpaces = queryString.split('+').join(' ');
const queryString = 'q=query+string+parameters';
const withSpaces = queryString.replace(/\+/g, ' ');
const queryString = 'q=query+string+parameters';
const withSpaces = queryString.replaceAll('+', ' ');

[fit] STAGE 3


globalThis 

Jordan Harband
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');
};

import() 
Domenic Denicola
<!DOCTYPE html>
<nav>
  <a href="books.html" data-entry-module="books">Books</a>
  <a href="movies.html" data-entry-module="movies">Movies</a>
  <a href="video-games.html" data-entry-module="video-games">Video Games</a>
</nav>

<main>Content will load here!</main>

<script>
  const main = document.querySelector("main");
  for (const link of document.querySelectorAll("nav > a")) {
    link.addEventListener("click", e => {
      e.preventDefault();

      import(`./section-modules/${link.dataset.entryModule}.js`)
        .then(module => {
          module.loadPageInto(main);
        })
        .catch(err => {
          main.textContent = err.message;
        });
    });
  }
</script>

Legacy RegExp features in JavaScript 

Mark Miller + Claude Pache
RegExpAlloc( newTarget );

RegExpBuiltInExec( R, S );

RegExp.input;

RegExp.prototype.compile( pattern, flags ); // modifications

BigInt 

Daniel Ehrenberg
const theBiggestInt = 9007199254740991n;

const alsoHuge = BigInt(9007199254740991);
// ↪ 9007199254740991n

const hugeButString = BigInt('9007199254740991');
// ↪ 9007199254740991n

import.meta

Domenic Denicola
(async () => {
  const response = await fetch(new URL("../hamsters.jpg", import.meta.url));
  const blob = await response.blob();

  const size = import.meta.scriptElement.dataset.size || 300;

  const image = new Image();
  image.src = URL.createObjectURL(blob);
  image.width = image.height = size;

  document.body.appendChild(image);
})();

Private instance methods and accessors

Daniel Ehrenberg + Kevin Gibbons
class Counter extends HTMLElement {
  #xValue = 0;

  get #x() { return #xValue; }
  set #x(value) {
    this.#xValue = value; 
    window.requestAnimationFrame(this.#render.bind(this));
  }

  #clicked() {
    this.#x++;
  }

  constructor() {
    super();
    this.onclick = this.#clicked.bind(this);
  }

  connectedCallback() { this.#render(); }

  #render() {
    this.textContent = this.#x.toString();
  }
}
window.customElements.define('num-counter', Counter);

Class Public Instance Fields & Private Instance Fields

Daniel Ehrenberg + Jeff Morrison + Kevin SmithKevin Gibbons
class X {
  #foo;
  method() {
    console.log(this.#foo)
  }
}
class X {
  bar;
  method() {
    console.log(this.bar)
  }
}

Static class fields and private static methods 

Shu-Yu Guo + Daniel Ehrenberg
class ColorFinder {
  static #red = "#ff0000";
  static #blue = "#00ff00";
  static #green = "#0000ff";
  
  static colorName(name) {
    switch (name) {
      case "red": return ColorFinder.#red;
      case "blue": return ColorFinder.#blue;
      case "green": return ColorFinder.#green;
      default: throw new RangeError("unknown color");
    }
  }

  static #setColor(name) {}
}

Hashbang Grammar 
Bradley Farias
#!/usr/bin/env node
// in the Script Goal
'use strict';
console.log(1);
#!/usr/bin/env node
// in the Module Goal
export {};
console.log(1);

Promise.allSettled 
Mathias Bynens
const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ];

const results = await Promise.allSettled(promises);
const errors = results
  .filter(p => p.status === 'rejected')
  .map(p => p.reason);
// We know all API calls have finished. We use finally but allSettled will never reject.
Promise.allSettled(requests).finally(() => {
  console.log('All requests are completed: either failed or succeeded, I don’t care');
  removeLoadingIndicator();
});

Numeric separators 

Sam Goto + Rick Waldron
let budget = 1_000_000_000_000;

// What is the value of `budget`? It's 1 trillion!
// 
// Let's confirm:
console.log(budget === 10 ** 12); // true
let nibbles = 0b1010_0001_1000_0101;

// Is bit 7 on? It sure is!
// 0b1010_0001_1000_0101
//             ^
//             
// We can double check: 
console.log(!!(nibbles & (1 << 7))); // true
// Messages are sent as 24 bit values, but should be 
// treated as 3 distinct bytes:
let message = 0xA0_B0_C0;

[fit] STAGE 4


String.prototype.matchAll

* Jordan Harband
* Formalized March 2019
* ES2020
npm install string.prototype.matchall

String.prototype.matchAll
const regex = /t(e)(st(\d?))/g;
const string = 'test1test2';
const matches = string.matchAll(regex);
for (const match of matches) {
  console.log(match);
}
/*
['test1', 'e', 'st1', '1', index: 0, input: 'test1test2', groups: undefined]
['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', groups: undefined]
*/
//  Unlike match() which returns an array on a global search, matchAll() returns an iterable object 

Optional catch binding

* Michael Ficarra
* May 2018
* ES2019
try {
  // try to use a web feature which may not be implemented
} catch (unused) {
  // fall back to a less desirable web feature with broader support
}
try {
  // ...
} catch {
  // ...
}

JSON superset

* Mark Miller + Mathias Bynens
* Formalized May 2018
* ES2019
const LS = "";
const PS = eval("'\u2029'");

//JSON strings can contain unescaped U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR characters while ECMAScript strings cannot.


Symbol.prototype.description

* Michael Ficarra
* Formalized November 2018
* ES2019
const sym = Symbol('The description');

assert.equal(String(sym), 'Symbol(The description)');

assert.equal(sym.description, 'The description');

Function.prototype.toString revision

* Michael Ficarra
* Formalized November 2018
* ES2019
isNaN.toString()
"function isNaN() { [native code] }"
class GIDS { foo() { /*hello*/ } }
undefined
GIDS.prototype.foo.toString()
"foo() { /*hello*/ }"

Object.fromEntries Jordan 

* HarbandKevin Gibbons 
* Formalized January 2019
* ES2019
const obj = Object.fromEntries([['a', 0], ['b', 1]]); 
// { a: 0, b: 1 }
const obj3 = { abc: 1, def: 2, ghij: 3 };
res = Object.fromEntries(
  Object.entries(obj)
  .filter(([ key, val ]) => key.length === 3)
  .map(([ key, val ]) => [ key, val * 2 ])
);
// res is { 'abc': 2, 'def': 4 }

Well-formed JSON.stringify 

* Mathias Bynens
* Formalized January 2019
* ES2019
// Non-BMP characters still serialize to surrogate pairs.
JSON.stringify('𝌆')
// → '"𝌆"'
JSON.stringify('\uD834\uDF06')
// → '"𝌆"'

// Unpaired surrogate code units will serialize to escape sequences.
JSON.stringify('\uDF06\uD834')
// → '"\\udf06\\ud834"'
JSON.stringify('\uDEAD')
// → '"\\udead"'

String.prototype.{trimStart,trimEnd} 

* Sebastian Markbåge + Mathias Bynens
* Formalized January 2019
* ES2019
"    Hey JS!".trimStart(); // "Hey JS!"

"    Hey JS!    ".trimEnd();// "    Hey JS!"

// P.S: trimLeft/trimRight are aliases.

Array.prototype.{flat,flatMap}

* Brian Terlson + Michael Ficarra 
* Formalized January 2019
* ES2019
let arr1 = [1, 2, 3, 4];

arr1.map(x => [x * 2]); 
// [[2], [4], [6], [8]]

arr1.flatMap(x => [x * 2]);
// [2, 4, 6, 8]

// only one level is flattened
arr1.flatMap(x => [[x * 2]]);
// [[2], [4], [6], [8]]
let arr1 = [1, 2, [3, 4]];
arr1.flat(); 
// [1, 2, 3, 4]

let arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]

let arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]

Lifting template literal restriction

* Tim Disney
* Formalized March 2017
* ES2018
// 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!`

s (dotAll) flag for regular expressions 

* Brian Terlson + Mathias Bynens 
* Formalized November 2017
* ES2018
const re = /foo.bar/s; // Or, `const re = new RegExp('foo.bar', 's');`.
re.test('foo\nbar');
// → true
re.dotAll
// → true
re.flags
// → 's'

/foo.bar/s.test('foo\nbar');
// → true

RegExp named capture groups 

* Daniel Ehrenberg + Brian Terlson + Mathias Bynens
* Formalized November 2017
* ES2018
let {one, two} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar');
console.log(`one: ${one}, two: ${two}`);  // prints one: foo, two: bar

Rest/Spread Properties 

* Sebastian Markbåge
* Formalized January 2018
* ES2018
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x; // 1
y; // 2
z; // { a: 3, b: 4 }
let n = { x, y, ...z };
n; // { x: 1, y: 2, a: 3, b: 4 }

---

```js
RegExp Lookbehind Assertions 

* Daniel Ehrenberg + Mathias Bynens
* Formalized January 2018
* ES2018
const str = '1947';

// (?<=(\d+)(\d+))$/ => (947) and (1)
// Greediness proceeds from right to left


// match[1] => 947 and match[2] => 1
// Numbering capture groups

// /(?<=\1(.))/
// Referring to capture groups

// /(?<!.)/
// Negative assertions

RegExp Unicode Property Escapes 

* Brian Terlson + Daniel Ehrenberg + Mathias Bynens
* Formalized January 2018
* ES2018
const regexGreekSymbol = /\p{Script=Greek}/u;
regexGreekSymbol.test('π');
// → true

Promise.prototype.finally

* Jordan Harband
* Formalized January 2018
* ES2018
somePromise()
.then(() => {})
.catch(() => {})
.finally(() => {})

Asynchronous Iteration 

* Domenic Denicola
* Formalized January 2018
* ES2018
const { value, done } = syncIterator.next();

asyncIterator.next().then(({ value, done }) => /* ... */);
for await (const line of readLines(filePath)) {
  console.log(line);
}

Object.values/Object.entries 

* Jordan Harband
* Formalized March 2016
* ES2017
const obj1= { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]

// array like object
const obj2 = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]

// array like object with random key ordering
const anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.entries(anObj)); // [ ['2', 'b'], ['7', 'c'], ['100', 'a'] ]

console.log(Object.values(anObj));
// ['a', 'b', 'c']

String.prototype.{padStart,padEnd} 

* Jordan Harband + Rick Waldron
* Formalized May 2016
* ES2017
const fullNumber = '2034399002125581';
const last4Digits = fullNumber.slice(-4);
const maskedNumber = last4Digits.padStart(fullNumber.length, '*');
console.log(maskedNumber);
// expected output: "************5581"
const str1 = 'Waiting';
console.log(str1.padEnd(25, '.'));
// expected output: "Waiting........"

Object.getOwnPropertyDescriptors

* Jordan Harband + Andrea Giammarchi
* Formalized May 2016
* ES2017
const object1 = {
  property1: 42
};

const descriptors1 = Object.getOwnPropertyDescriptors(object1);

console.log(descriptors1.property1.writable);
// expected output: true

console.log(descriptors1.property1.value);
// expected output: 42

Trailing commas in function parameter lists and calls 

* Jeff Morrison
* Formalized July 2016
* ES2017
function clownPuppiesEverywhere(
  param1,
  param2, // Next parameter that's added only has to add a new line, not modify this line
) { /* ... */ }

clownPuppiesEverywhere(
  'foo',
  'bar', // Next parameter that's added only has to add a new line, not modify this line
);

Async functions 

* Brian Terlson
* Formalized July 2016
* ES2017
async fetchComic() {
    const fetch = require('node-fetch');
    return await (await fetch('http://xkcd-imgs.herokuapp.com/')).json();
}

Shared memory and atomics 

* Lars T Hansen
* Formalized January 2017
* ES2017
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
}

Array.prototype.includes 

* Domenic Denicola + Rick Waldron
* Formalized November 2015
* ES2016
assert([1, 2, 3].includes(2) === true);
assert([1, 2, 3].includes(4) === false);

assert([1, 2, NaN].includes(NaN) === true);

Exponentiation Operator

* Rick Waldron 
* Formalized January 2016
* ES2016
// x ** y

let squared = 2 ** 2;
// same as: 2 * 2

let cubed = 2 ** 3;
// same as: 2 * 2 * 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment