ECMAScript as an evolving language

About me

  • Lenz Weber (@phry on Twitter, phryneas everywhere else)
  • Developer at
  • Working in professional web development since 15 years
  • In love with the Web, Open Source, Linux and Security
  • Just getting used to conference speaking, so bear with me

Let's get started

ECMAScript? JavaScript!

  • ECMAScript is the specification behind JavaScript - the baseline every engine should support
  • additionally, for front-end development, the WhatWG DOM Living Standard describes APIs that can be used for DOM manipulation

A short History of ECMAScript

  • 1997-1999, ECMAScript 1-3 were released

And a look at the browser

(getting a real history here is almost impossible, so take these examples)

  • Element.querySelector() started being supported ~2009
  • Element.classList() started being supported ~2012
  • fetch as a unified API for XHR Requests is supported since 2015-2017 (no IE)

All those things were always possible - but differed from browser to browser.

So... 1999 to 2015...

  • Many features were not available cross-browser
  • Two types of libraries started surfacing, hiding the browser-specific implementations:
  • DOM manipulation (e.g. jquery, mootools), making up for missing DOM manipluation functionality
  • Utility (e.g. underscore, lodash, mootools, jquery) to provide ease-of-use where the language was lacking

Then the Standards caught up and browsers started converging (and became evergreen!)

Today, you don't need those libraries any more. Modern browsers support everything we talked about.

Well, except IE11. But for that, we have polyfills. πŸŽ†

What is a polyfill?

A polyfill detects if a browser supports a feature like window.fetch, and if that is missing, shims an alternative implementation in place of the original functionality.

Side Note: PonyFills

A ponyfill acts like a polyfill, but does not inject itself in place of a missing functionality, but exports either the original implementation or a shim.
This is much less disruptive - if you have the choice, prefer ponyfills to polyfills.

All our problems are solved

...and they lived happily every after ...

πŸ‘ΈπŸ‘Έ/πŸ€΄πŸ‘Έ/🀴🀴 -> πŸ¦„ -> 🌈

Okay, I lied

You can polyfill missing functions, but you can't polyfill unsupported syntax.

So... let's transpile.

The idea behind it:

  • Write ES β‰₯ 6
  • Use a transpiler to convert it into ES5 (or even ES3)
  • If you want to get fancy: to every browser, ship a form of ECMAScript it is compatible with
  • add Polyfills for old browsers where necessary

We write this

1. async function getMovies() {
2. const response = await fetch(
3. 'http://example.com/movies.json'
4. );
5. const data = await response.json();
6. return data;
7. }

And IE11 gets this

1. "use strict";
2.
3. var getMovies = (function() {
4. var _ref = _asyncToGenerator(
5. /*#__PURE__*/ regeneratorRuntime.mark(function _callee() {
6. var response, data;
7. return regeneratorRuntime.wrap(
8. function _callee$(_context) {
9. while (1) {
10. switch ((_context.prev = _context.next)) {
11. case 0:
12. _context.next = 2;
13. return fetch("http://example.com/movies.json");
14.
15. case 2:
16. response = _context.sent;
17. _context.next = 5;
18. return response.json();
19.
20. case 5:
21. data = _context.sent;
22. return _context.abrupt("return", data);
23.
24. case 7:
25. case "end":
26. return _context.stop();
27. }
28. }
29. },
30. _callee,
31. this
32. );
33. })
34. );
35.
36. return function getMovies() {
37. return _ref.apply(this, arguments);
38. };
39. })();
40.
41. function _asyncToGenerator(fn) {
42. return function() {
43. var gen = fn.apply(this, arguments);
44. return new Promise(function(resolve, reject) {
45. function step(key, arg) {
46. try {
47. var info = gen[key](arg);
48. var value = info.value;
49. } catch (error) {
50. reject(error);
51. return;
52. }
53. if (info.done) {
54. resolve(value);
55. } else {
56. return Promise.resolve(value).then(
57. function(value) {
58. step("next", value);
59. },
60. function(err) {
61. step("throw", err);
62. }
63. );
64. }
65. }
66. return step("next");
67. });
68. };
69. }
70.

a state machine

"

So...

We have found ways to use modern standards in all browsers (at some cost, but that's unavoidable)

Why should we stop here?

Languages that extend JavaScript with a type system

TypeScript

1. interface Person {
2. firstName: string;
3. lastName: string;
4. }
5.
6. class Student implements Person {
7. fullName: string;
8. constructor(public firstName: string, public middleInitial: string, public lastName: string) {
9. this.fullName = firstName + " " + middleInitial + " " + lastName;
10. }
11. }
12.
13. function greeter(person : Person) {
14. return "Hello, " + person.firstName + " " + person.lastName;
15. }
16.
17. let user = new Student("Jane", "M.", "User");
18.
19. console.log(greeter(user));

Reads & writes like JavaScript, but has a powerful type system

Completely different languages

Clojure

1. (ns example
2. (:require [reagent.core :as r]))
3.
4. (defn simple-component []
5. [:div
6. [:p "I am a component!"]
7. [:p.someclass
8. "I have " [:strong "bold"]
9. [:span {:style {:color "red"}} " and red "] "text."]])
10.
11. (defn render-simple []
12. (r/render [simple-component]
13. (.-body js/document)))

Can be run in the JVM or transpiled to JavaScript

Reason

1. type user = { firstName: string, lastName: string };
2.
3. let user: user = {
4. firstName: "Harper",
5. lastName: "Perez"
6. };
7.
8. let formatName user =>
9. user.firstName ^ " " ^ user.lastName;
10.
11. let hello =
12. (ReactRe.stringToElement ("Hello, " ^ formatName user));
13.
14. let header =
15. <h1 title=(formatName user)>
16. hello
17. </h1>;
18.
19. ReactDOMRe.renderToElementWithId header "root";

OCaml dicalect that transpiles to JavaScript

New syntax to write JavaScript

JSX

1. const TestComponent = (props) => (
2. <div className="card">
3. <h1 style={{ color: "green" }}>{props.title}</h1>
4. <p>{props.content}</p>
5. </div>
6. );

a way of writing JavaScript that looks shockingly like HTML

transpiles to

1. var TestComponent = function TestComponent(props) {
2. return React.createElement(
3. "div",
4. { className: "card" },
5. React.createElement(
6. "h1",
7. { style: { color: "green" } },
8. props.title
9. ),
10. React.createElement(
11. "p",
12. null,
13. props.content
14. )
15. );
16. };

Use JSNext

(or: ECMAScript as an evolving language)

We can also write Syntax that isn't even part of any standard yet!

The ECMA TC39

  • The committee that decides on new ECMAScript features
  • Accepts minor suggestions as PR/Issue on github
  • New feature Proposals are developed in separate GitHub repositories and go through 4 stages

The way of a Proposal

  • Document your problem & solution/suggestion
  • Discuss it with the community
  • Find a TC39 member that will act as Champion for your proposals
  • Go through the four stages: Proposal, Draft, Candidate, Finished

Using a Proposal today

  • Find an interesting proposal at https://github.com/tc39/proposals
  • Stage 2 proposals usually come with ready-to-use transpiler plugins
  • Just use it
  • If you have issues or suggestions: join the discussion πŸ’–

an example from the decorator proposal

1. @defineElement('num-counter')
2. class Counter extends HTMLElement {
3. @observed #x = 0;
4.
5. @bound
6. #clicked() {
7. this.#x++;
8. }
9.
10. constructor() {
11. super();
12. this.onclick = this.#clicked;
13. }
14.
15. connectedCallback() { this.render(); }
16.
17. @bound
18. render() {
19. this.textContent = this.#x.toString();
20. }
21. }

the pipeline proposal

1. let result = exclaim(capitalize(doubleSay("hello")));
2. result //=> "Hello, hello!"
3.
4. let result = "hello"
5. |> doubleSay
6. |> capitalize
7. |> exclaim;
8.
9. result //=> "Hello, hello!"

combined with the partial application proposal

1. function double (x) { return x + x; }
2. function add (x, y) { return x + y; }
3. function boundScore (min, max, score) {
4. return Math.max(min, Math.min(max, score));
5. }
6.
7. let person = { score: 25 };
8.
9. let newScore = person.score
10. |> double
11. |> add(7, ?)
12. |> boundScore(0, 100, ?);
13.
14. newScore //=> 57

What this means for Developers:

  • You really should be learning ES6 by now
  • And then probably some TypeScript or Flow
  • Choose your own Adventure with ESNext ;)

Are all problems solved now?

Almost.

You won't be able to polyfill or transpile real "Browser" features like multithreading using WebWorkers.

Addendum

Source: heise.de

  • Array<F>.prototype.flatMap<T>(callback: (elem: F, idx: number): T[]): T[]
  • Array<F | F[]>.prototype.flattensmooshflat(): F[]
  • String.prototype.trimStart(): string
  • String.prototype.trimEnd(): string
  • Symbol.prototype.description: string
  • try {} catch {} without having to receive the error
  • Array.prototype.sort is now stable!
  • better handling of UTF-16 in JSON.stringify

Time for Questions & Discussion

By the way...

We are hiring!

(talk to me)