ES6+
O presente e o futuro do Javascript
JS?
ES5?
ESNext?
Versões da ECMA-262
- ES1 - 1997
- ES2 - 1998
- ES3 - 1999
-
ES4- gongada pela Microsoft - ES5 - 2009
- ES6 - Junho de 2015
- ES7 - Junho de 2016
- ES8 - Junho de 2017
- ES9 - coming soon!
TC39
Para ver todas as features
ES6
O renascimento

let e const
Arrow function
spread
Destructuring
For of
Default parameter
Map/Set/WeakMap/WeakSet
Classes
Promises
Generators
Template literals
var a = "lindo";
var b = "bbk";
console.log(`Victor é ${a} and
também é ${b}.`);
Trailing comma
const palavrasApenas = [
"almofada",
"chafariz",
"salamanda",
];
const palavrasApenasComNumeros = [
"almofada": 1,
"chafariz": 2,
"salamanda": 3,
];
Array: from, of, find, findIndex, fill
Object: assign
ES7/ES2016

Operador de exponenciação
const byte = 2 ** 8;
Array.includes
const pessoasPresentes = ["Josefina", "Mário Alberto"];
pessoasPresentes.includes("Josefina"); // true
pessoasPresentes.includes("Stephanie"); // false
ES8/ES2017

mostly async, tho
Async/Await
async function getOrgs(user) {
const url =
`https://api.github.com/users/${user}/orgs`;
const orgs = await fetch(url).then(res => res.json());
return orgs;
}
Object: values e entries
const peopleById = {
dygufa: "Rodrigo Araújo",
vhfmag: "Victor Magalhães",
};
const ids = Object.keys(peopleById);
const names = Object.values(peopleById);
for (const [id, name] of Object.entries(peopleById) {
console.log(`id: ${id}, nome: ${name}`);
}
String: padStart e padEnd
function formatDate(date) {
const month = date.getMonth() + 1;
const date = date.getDate();
const year = date.getFullYear();
return [date, month, year]
.map(x => x.toString().padStart(2, "0"))
.join("/");
}
formatDate(new Date); // "10/05/2018"
ES9/ES2018

Rest/Spread
({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40});
console.log(a); // 10
console.log(b); // 20
console.log(rest); //{c: 30, d: 40}
Iteradores Assíncronos
import React from "react";
import { render } from "react-dom";
const sleep = (n) => new Promise(res => setTimeout(res, n));
async function* ping(n) {
let count = 0;
while (true) {
await sleep(n);
yield ++count;
}
}
class App extends React.Component {
state = { seconds: 0 };
async componentDidMount() {
for await (const seconds of ping(1000)) this.setState({ seconds });
}
render() {
return (
<div>
<img src="https://media1.giphy.com/media/qQx7B5z3hG19K/giphy.gif" />
<h2>You have been rickrolled for {this.state.seconds} seconds</h2>
</div>
);
}
}
render(<App />, document.getElementById("root"));
Promise.finally
fetch("some.api/endpoint")
.then(res => res.json())
.catch(() => new Error("oh shit"))
.finally(() => model.cleanStuff())
Regex named captured groups
const dateRegexp = /(?<date>\d+)\/(?<month>\d+)\/(?<year>\d+)/;
let {
groups: { date, year, month }
} = dateRegexp.exec("12/01/2018")
Futuro (maybe?)

stage-3
-
candidate
Array: flatMap & flatten
const pessoas = [
{ name: "Victor", grades: [8, 5, 8] },
{ name: "Dygufa", grades: [9, 7, 6] },
{ name: "Clara", grades: [8.5, 5, 9] },
];
const todasAsNotas = pessoas
.flatMap(({ grades }) => grades);
const todasAsNotas2 = pessoas
.map(({ grades }) => grades)
.flatten();
String: trimStart & trimEnd
const pessoas = [
{ name: "Victor", grades: [8, 5, 8] },
{ name: "Dygufa", grades: [9, 7, 6] },
{ name: "Clara", grades: [8.5, 5, 9] },
];
const todasAsNotas = pessoas
.flatMap(({ grades }) => grades);
const todasAsNotas2 = pessoas
.map(({ grades }) => grades)
.flatten();
Campos públicos e privados em classes
class Store {
#user = null;
lastUpdated = new Date();
async fetchUser() {
const res = await fetch(/**/);
this.#user = await res.json();
this.#onUpdate();
}
#onUpdate() {
this.lastUpdated = new Date();
}
}
import() - import dinâmico
import { flatMap } from "lodash";
async function getAllCells(src) {
if (src instanceof File) {
const XLSX = await import("xlsx");
return flatMap(XLSX.fromFile(src).sheets[0]);
} else {
return flatMap(src, x => x);
}
}
stage-2
-
draft
decoradores
@autobind
class Store {
@observable user = null;
async fetchUser(id) {
return await fetch(/**/)
.then(res => res.json());
}
@action clearUser() {
this.user = null;
}
@computed userId() {
return this.user && this.user.id;
}
}
campos estáticos públicos e privados
class Utils {
static #parseDate(raw) {
return moment(raw).toDate();
}
static parseUser(raw) {
return { ...raw, birthday: Utils.#parseDate(raw) };
}
}
throw como expressão
function getEncoder(encoding = throw new Error("Argument required")) {
return encoding === "utf8" ? new UTF8Encoder()
: encoding === "utf16le" ? new UTF16Encoder(false)
: encoding === "utf16be" ? new UTF16Encoder(true)
: throw new Error("Unsupported encoding");
}
stage-1
-
proposal
observables
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 cleanup function which will cancel the event stream
return () => {
// Detach the event handler from the element
element.removeEventListener(eventName, handler, true);
};
});
}
function commandKeys(element) {
let keyCommands = { "38": "up", "40": "down" };
return listen(element, "keydown")
.filter(event => event.keyCode in keyCommands)
.map(event => keyCommands[event.keyCode])
}
let subscription = commandKeys(inputElement).subscribe({
next(val) { console.log("Received key command: " + val) },
error(err) { console.log("Received an error: " + err) },
complete() { console.log("Stream complete") },
});
temporal
new CivilDate(year, month, day);
new CivilTime(hour, minute[[[, second], millisecond], nanosecond]);
new CivilDateTime(year, month, day, hour, minute, [...]);
new Instant(milliseconds[, nanoseconds]);
new ZonedInstant(instant, timeZone);
operador pipeline
const doubleSay = (str) => str + ", " + str;
const capitalize = ([first, ...rest]) =>
first.toUpperCase() + rest.join("");
const exclaim = (str) => str + '!';
let result1 = exclaim(capitalize(doubleSay("hello")));
let result2 = "hello"
|> doubleSay
|> capitalize
|> exclaim;
result1 // "Hello, hello!"
result1 === result2 // true
partial application
let newScore = player.score
|> somar(7, ?)
|> limitar(0, 100, ?);
const maxGreaterThanZero = Math.max(0, ...);
maxGreaterThanZero(1, 2); // 2
maxGreaterThanZero(-1, -2); // 0
nullish coalescing e optional chaining
async function makeRequest(options) {
const maxCacheTime = options?.maxCacheTime ?? 1E4;
const skipHandshake = options?.skipHandshake ?? true;
const userName = options?.userName ?? "@anonymous";
// do stuff
}
do expression
return (
<nav>
<Home />
{
do {
if (loggedIn) {
<LogoutButton />
} else {
<LoginButton />
}
}
}
</nav>
)
slice notation
const grades = [9, 8, 10, 5, 7];
const someGrades = grades[2:4];
const tail = grades[1:];
const evens = grades[::2];
const odds = grades[1::2];
const reverse = grades[::-1];
stage-0
-
strawman
pattern matching
const res = await fetch(jsonService)
const val = match (res) {
{status: 200, headers: {'Content-Length': s}} => `size is ${s}`,
{status: 404} => 'JSON not found',
{status} if (status >= 400) => throw new RequestError(res)
}
return (
<Fetch url={API_URL}>{
props => match (props) {
{loading} if (loading) => <Loading />,
{error} => <Error error={error} />,
{data} => <Page data={data} />
}
}</Fetch>
);
obrigado!
ES6+
By Victor Magalhães
ES6+
Um panorama das principais features das versões mais recentes do EcmaScript!
- 703