Upload
tomasz-dziuda
View
182
Download
1
Embed Size (px)
Citation preview
ECMAScript 2015Tomasz Dziuda
meet.js Łódź @ 9.VI.2015
About me@dziudek [email protected]
http://dziudek.pl
Lead Developer @ GavickPro
Organizer of: • WordUp Łódź, • JoomlaDay Poland 2013, • WordCamp Poland 2014, • WordCamp Poland 2015
http://dziudek.github.io/dev-links/
ES2015 Today
Source: http://kangax.github.io/compat-table/es6/ screenshot from: 31/5/2015
https://babeljs.io/
ES2015 Features
Enhanced Object Literals
var car = {speed: 100,getSpeed() {return this.speed;
}}
// car.speed() => 100;
var chapter = 2;
var bookState = {[“ch” + chapter]: “Chapter ” + chapter,[“getChapter” + chapter]() {return this[“ch” + chapter];
}}
// bookState.ch2 => “Chapter 2”// bookState.getChapter2() => “Chapter 2”
Classes
class Person {constructor(name, age) {this.name = name;this.age = age
}toString() {return “Person: ” + this.name;
}}
Inheritance
class Person extends Mammal {constructor(name, age) {super();this.name = name;this.age = age
}toString() {return “Person: ” + this.name;
}}
static, get, set
class URLHelper {static hashVal() {return location.hash.replace(‘#’,’’);
}}
URLHelper.hashVal(); // http://domain.com/#top => “top”
class Person {constructor(name, age) {this._name = name;this._age = age
}get name() {return this._name;
}set name(newName) {this._name = newName;
}}
Built-ins subclassing
class MyArray extends Array {last() {return this[this.length - 1];
}}
Abstract classes
class Base {constructor () {if (new.target === Base) {throw TypeError("new of abstract class Base”);
}}
}
Modules
// file helper/linker.jsexport var separator = ‘,’;export function link (arr) {
return arr.join(separator); }
// file helper/linker.js
export {separator};
export {separator as s};
export {separator} from “linker”;
export {separator as s} from “linker”;
// file app.jsimport {separator, link} from ‘helper/linker’;
// file app.jsimport {separator, link} from ‘helper/linker’;
// file app.jsimport * as linker from ‘helper/linker’;// linker.separator / linker.link
// file app.jsimport {separator, link} from ‘helper/linker’;
// file app.jsimport * as linker from ‘helper/linker’;// linker.separator / linker.link
// file app.jsimport {separator as s} from ‘helper/linker’;
// file helper/linker.jsexport var separator = ‘,’;export default function(arr) {
return arr.join(separator); }
// file app.jsimport link from ‘helper/linker’;
// file app.jsimport link from ‘helper/linker’;
// file app.jsimport link, {separator} from ‘helper/linker’;
Template Strings
var msg = `<ul> <li>Item I</li> <li>Item II</li> <li>Item III</li> <li>Item IV</li> <li>Item V</li></ul>`;
var username = “John”;var msg = `Hello, ${username}`;// msg returns “Hello, John”
var firstname = “John”;var lastname = “ Doe”var msg = `Hello, ${firstname + lastname}`;// msg returns “Hello, John Doe”
var fName = “John”;var msg = `Hello, ${fName.toUpperCase()}`;// msg returns “Hello, JOHN”
var total = 100;var VAT = 23;var finalPrice = ‘’; // we’ll have an error without it
var msg = parseVAT`Sum: ${total} + VAT ${VAT}% = ${finalPrice}`;// "Sum: 100 + VAT 23% = 123"
function parseVAT(parts, total, VAT) { var output = "",
i = 0; while (i < parts.length) { output += parts[i++]; if (i < arguments.length) { output += arguments[i]; }
if(i === 3){ output += total * (100 + VAT) / 100.0; } } return output;}
function parseVAT(parts, total, VAT) { var output = "",
i = 0; while (i < parts.length) { output += parts[i++]; if (i < arguments.length) { output += arguments[i]; }
if(i === 3){ output += total * (100 + VAT) / 100.0; } } return output;}
function parseVAT(parts, total, VAT) { var output = "",
i = 0; while (i < parts.length) { output += parts[i++]; if (i < arguments.length) { output += arguments[i]; }
if(i === 3){ output += total * (100 + VAT) / 100.0; } } return output;}
function parseVAT(parts, total, VAT) { var output = "",
i = 0; while (i < parts.length) { output += parts[i++]; if (i < arguments.length) { output += arguments[i]; }
if(i === 3){ output += total * (100 + VAT) / 100.0; } } return output;}
http://jsperf.com/es6-string-literals-vs-string-concatenation
http://jsperf.com/es6-string-literals-vs-string-concatenation
Constants
const PI = 3.141593;
const ĘĆ = 1.858407;
var pięć = PI + ĘĆ;
const PI = 3.141593;
PI = 3.14; // not work
const person = { name: “John” };
person.name = “Adam”; // Correct - use Object.freeze
person.age = 25; // Correct - use Object.seal
const PI = 3.141593;
PI = 3.14; // not work
const person = { name: “John” };
person.name = “Adam”; // Correct - use Object.freeze
person.age = 25; // Correct - use Object.seal
const PI = 3.141593;
PI = 3.14; // not work
const person = { name: “John” };
person.name = “Adam”; // Correct - use Object.freeze
person.age = 25; // Correct - use Object.seal
Block scope
{ function test() {
return 1; }
test() === 1; // True
{ function test() {
return 2; }
test() === 2; // True }
test() === 1; // Still true}
{ function test() {
return 1; }
test() === 1; // True
{ function test() {
return 2; }
test() === 2; // True }
test() === 1; // Still true}
{ function test() {
return 1; }
test() === 1; // True
{ function test() {
return 2; }
test() === 2; // True }
test() === 1; // Still true}
{ function test() {
return 1; }
test() === 1; // True
{ function test() {
return 2; }
test() === 2; // True }
test() === 1; // Still true}
{ function test() {
return 1; }
test() === 1; // True
{ function test() {
return 2; }
test() === 2; // True }
test() === 1; // Still true}
var arr = [1,2,3];
for (let i = 0; i < arr.length; i++) { var temp = arr[i];}
console.log(i); // undefinedconsole.log(temp); // 3
let name = “John”;
let name = “Alex”; // Error
Arrow functions
function (fName, lName) {return fName + ‘ ‘ + lName;
}
(fName, lName) => fName + ‘ ‘ + lName;
[1, 2, 3].map(n => n * 2);
[1,2,3].filter(n => n % 2 === 0);
var person = () => ({name:“John”, age:25});
[1, 2, 3].map(n => n * 2);
[1,2,3].filter(n => n % 2 === 0);
var person = () => ({name:“John”, age:25});
[1, 2, 3].map(n => n * 2);
[1,2,3].filter(n => n % 2 === 0);
var person = () => ({name:“John”, age:25});
function Timer(){ this.time = 0;
setInterval(function() { this.time++; // won’t work }, 1000);}
var t = new Timer();
function Timer(){ this.time = 0; // below line will affect the time setInterval(() => this.time++, 1000);}
var t = new Timer();
fetch(url).then(response => response.json())
.then(data => console.log(data))
.catch(e => console.log(“Error!”));
Shorthand assignment
let name = “John”;
let person = {name};
// person = {name: “John”}
let name = “John”;
let person = {name};
// person = {name: “John”}
Destructuring
var x = 1;var y = 2;
[x, y] = [y, x]; // x=2, y=1
function names() {return [“John”, “Alex“];
}
var p1, p2;
[p1, p2] = names();
function names() {return [“John”, “Alex“, “Max”];
}
var p1, p2;
[p1, ,p2] = names();
var names = ["Alex", "John", "Max"];
var [p1, p2, p3] = names;
var names = {p1:“Alex”, p2:”John", p3:”Max”
};
var {p1, p2, p3} = names;
/* p1 = Alexp2 = Johnp3 = Max*/
function date({ day:d, month:m, year:y }) {return d + ‘-’ + m + ‘-’ + y;
}
date({ day: 20, month: 10, year: 1988 });
Better parameter handling
function power(x, y = 2) {return Math.pow(x, y);
}
// f(2) => 4
function names(x, ...y) {return 1 + y.length;
}
// names(“Alex”, “John”, “Max”) => 3
function names(x, y, z) {return x + “ ” + y + “ ” + z;
}
names(…[“Alex”, “John”, “Max”]);
var a = [3,4,5];
var b = [1,2, …a];
// b => [1,2,3,4,5]
Symbols
let symbol1 = Symbol(“test”);let symbol2 = Symbol(“test”);
symbol1 === symbol2 // False
let objWithSymbol = {[Symbol(“year”)]: 2015
}
console.log(objWithSymbol); // {}
let objWithSymbol = {[Symbol(“year”)]: 2015
}
console.log(objWithSymbol); // {}
Object.getOwnPropertySymbols(objWithSymbol);// [Symbol(year)]
Iterators & Generators
let iterable = “abc”[Symbol.iterator]();
iterable.next(); // { value: “a”, done: false }iterable.next(); // { value: “b”, done: false }iterable.next(); // { value: “c”, done: false }iterable.next(); // { value: undefined, done: true }
Iterable• Array
• String
• Map
• Set
• arguments
• DOM queries
for .. of
for(let div of document.querySelectorAll('div')) { div.style.border = "1px solid red";}
var obj = { items: [1,2,3,4,5], [Symbol.iterator]() { let i = 0; let self = this; return { next() { return { done: (i >= self.items.length), value: self.items[i++] } } } }}
for(let n of obj) {console.log(n);
}// 1// 2// 3// 4// 5
function* gen(start, stop) {while(start <= stop) {yield start;start++;
}}
var r = gen(0, 2);
r.next(); // {value: 0, done: false}r.next(); // {value: 1, done: false}r.next(); // {value: 2, done: false}r.next(); // {value: undefined, done: true}
function* gen() {yield ‘start’;yield ‘middle’;yield ‘stop’;
}
var g = gen();
g.next(); // { value: ‘start’, done: false}g.next(); // { value: ‘middle’, done: false}g.next(); // { value: ‘stop’, done: false}
function* odd(max) {for(var i = 0; i <= max; i++) {if(i % 2) yield i;
}}
let odds = […odd(20)]// [1,3,5,7,9,11,13,15,17,19]
function* odd(max) {for(var i = 0; i <= max; i++) {if(i % 2) yield i;
}}
let odds = […odd(20)]// odds = [1,3,5,7,9,11,13,15,17,19]
let odds = [];
for (let n of odd(20)) { odds.push(n);}
// odds = [1,3,5,7,9,11,13,15,17,19]
Promises
Promise states
• pending === !fulfilled && !rejected
• fulfilled === success
• rejected === fail
function readFile(filename) {return new Promise(function(fulfill, reject) {
fs.readFile(filename, encoding, function(err, res) {if(err) reject(err);else fulfill(res);
});});
}
function readFile(filename) {return new Promise(function(fulfill, reject) {
fs.readFile(filename, encoding, function(err, res) {if(err) reject(err);else fulfill(res);
});});
}
function readFile(filename) {return new Promise(function(fulfill, reject) {
fs.readFile(filename, encoding, function(err, res) {if(err) reject(err);else fulfill(res);
});});
}
function readFile(filename) {return new Promise(function(fulfill, reject) {
fs.readFile(filename, encoding, function(err, res) {if(err) reject(err);else fulfill(res);
});});
}
readFile(‘data.json’, 'utf8').then(function (res){ return JSON.parse(res);});
readFile(‘data.json’, 'utf8').then(function (res){ return JSON.parse(res);});
readFile(‘data.json’, 'utf8').then(function (res){ return JSON.parse(res);}, function (err) {
console.log(err);});
readFile(‘data.json’, 'utf8').then(function (res){ return JSON.parse(res);}).catch(function(err) {
console.log(err);});
Promise.all([ readFile(‘data1.json’, 'utf8'), readFile(‘data2.json’, 'utf8'), readFile(‘data3.json’, 'utf8')]).then((data) => { let [ f1, f2, f3 ] = data;});
Promise.all([ readFile(‘data1.json’, 'utf8'), readFile(‘data2.json’, 'utf8'), readFile(‘data3.json’, 'utf8')]).then((data) => { let [ f1, f2, f3 ] = data;});
Promise.all([ readFile(‘data1.json’, 'utf8'), readFile(‘data2.json’, 'utf8'), readFile(‘data3.json’, 'utf8')]).then((data) => { let [ f1, f2, f3 ] = data;});
Promise.race([ readFile(‘data1.json’, 'utf8'), readFile(‘data2.json’, 'utf8'), readFile(‘data3.json’, 'utf8')]).then((data) => { let fastest = data;});
Proxies
var obj = {};
var observed = new Proxy(obj, { set(target, key, value, receiver) { console.log(key+'='+value); target[key] = value; }});
observed.x = 10; // x = 10
var obj = {};
var observed = new Proxy(obj, { set(target, key, value, receiver) { console.log(key+'='+value); target[key] = value; }});
observed.x = 10; // x = 10
var obj = {};
var observed = new Proxy(obj, { set(target, key, value, receiver) { console.log(key+'='+value); target[key] = value; }});
observed.x = 10; // x = 10
var obj = {};
var observed = new Proxy(obj, { set(target, key, value, receiver) { console.log(key+'='+value); target[key] = value; }});
observed.x = 10; // x = 10
var obj = {};
var observed = new Proxy(obj, { set(target, key, value, receiver) { console.log(key+'='+value); target[key] = value; }});
observed.x = 10; // x = 10
Maps & Sets
Set
• Used to store unique values
• Iterable
• Easily accessible size
var names = new Set();
names.add(“Doe”);names.add(“Johnson”);
names.has(“Doe”); // truenames.size; // 2
names.delete(“Johnson”); // truenames.size; // 1
var names = new Set();
names.add(“Doe”);names.add(“Johnson”);
names.has(“Doe”); // truenames.size; // 2
names.delete(“Johnson”); // truenames.size; // 1
var names = new Set();
names.add(“Doe”);names.add(“Johnson”);
names.has(“Doe”); // truenames.size; // 2
names.delete(“Johnson”); // truenames.size; // 1
var names = new Set();
names.add(“Doe”);names.add(“Johnson”);
names.has(“Doe”); // truenames.size; // 2
names.delete(“Johnson”); // truenames.size; // 1
var names = new Set();
names.add(“Doe”);names.add(“Johnson”);
names.has(“Doe”); // truenames.size; // 2
names.delete(“Johnson”); // truenames.size; // 1
for (let name of names) {console.log(name);
}
let nameArr = […names];
for (let name of names.keys()) {console.log(name);
}// names.keys() === names.values()
for (let name of names) {console.log(name);
}
let nameArr = […names];
for (let name of names.keys()) {console.log(name);
}// names.keys() === names.values()
for (let name of names) {console.log(name);
}
let nameArr = […names];
for (let name of names.keys()) {console.log(name);
}// names.keys() === names.values()
Map
• Used to store values connected with unique keys
• Iterable
• Easily accessible size
• key can be primitive, object or even function
var relations = new Map();
relations.set(“John”, “Mary”);relations.set(“Adam”, “Eve”);
relations.size; // 2relations.get(“Adam”); // “Eve”relations.delete(“Adam”); // truerelations.size; // 1
var relations = new Map();
relations.set(“John”, “Mary”);relations.set(“Adam”, “Eve”);
relations.size; // 2relations.get(“Adam”); // “Eve”relations.delete(“Adam”); // truerelations.size; // 1
var relations = new Map();
relations.set(“John”, “Mary”);relations.set(“Adam”, “Eve”);
relations.size; // 2relations.get(“Adam”); // “Eve”relations.delete(“Adam”); // truerelations.size; // 1
var relations = new Map();
relations.set(“John”, “Mary”);relations.set(“Adam”, “Eve”);
relations.size; // 2relations.get(“Adam”); // “Eve”relations.delete(“Adam”); // truerelations.size; // 1
var relations = new Map();
relations.set(“John”, “Mary”);relations.set(“Adam”, “Eve”);
relations.size; // 2relations.get(“Adam”); // “Eve”relations.delete(“Adam”); // truerelations.size; // 1
for (let [key, value] of relations) {console.log(key + “ & ” + value);
}
for (let [key, value] of relations.entries()) {console.log(key + “ & ” + value);
}
for (let key of relations.keys()) {console.log(key);
}
WeakMap vs. Map
• Doesn’t prevent GC
• no information about size
• Key can be only an object (function is object too)
let privateData = new WeakMap();
class MyClass { constructor(name, age) { privateData.set(this, { name: name, age: age }); }
getName() { return privateData.get(this).name; }
getAge() { return privateData.get(this).age; }}
let privateData = new WeakMap();
class Person { constructor(name, age) { privateData.set(this, { name: name, age: age }); }
getName() { return privateData.get(this).name; }
getAge() { return privateData.get(this).age; }}
let privateData = new WeakMap();
class Person { constructor(name, age) { privateData.set(this, { name: name, age: age }); }
getName() { return privateData.get(this).name; }
getAge() { return privateData.get(this).age; }}
let privateData = new WeakMap();
class Person { constructor(name, age) { privateData.set(this, { name: name, age: age }); }
getName() { return privateData.get(this).name; }
getAge() { return privateData.get(this).age; }}
// Without WeakMaplet p1 = new Person(“John”, 25);let p2 = new Person(“Adam”, 40);privateData.size; // 2
p1 = null;privateData.size; // 2
// Without WeakMaplet p1 = new Person(“John”, 25);let p2 = new Person(“Adam”, 40);privateData.size; // 2
p1 = null;privateData.size; // 2
WeakSet vs. Set• Doesn’t prevent GC
• non-iterable
• non-accessible element values
• no information about size
• key can be only an object
Built-in Methods
[1, 5, 3, 8].find(x => x > 2); // 5
“- ”.repeat(3); // “- - - ”
Object.assign(obj, {“a”: 1}, {“b”: 2});// obj = {“a”: 1, “b”: 2}
Math.sign(25); // 1Math.sign(0); // 0
Math.sign(-25); // -1
[1, 5, 3, 8].find(x => x > 2); // 5
“- ”.repeat(3); // “- - - ”
Object.assign(obj, {“a”: 1}, {“b”: 2});// obj = {“a”: 1, “b”: 2}
Math.sign(25); // 1Math.sign(0); // 0
Math.sign(-25); // -1
[1, 5, 3, 8].find(x => x > 2); // 5
“- ”.repeat(3); // “- - - ”
Object.assign(obj, {“a”: 1}, {“b”: 2});// obj = {“a”: 1, “b”: 2}
Math.sign(25); // 1Math.sign(0); // 0
Math.sign(-25); // -1
[1, 5, 3, 8].find(x => x > 2); // 5
“- ”.repeat(3); // “- - - ”
Object.assign(obj, {“a”: 1}, {“b”: 2});// obj = {“a”: 1, “b”: 2}
Math.sign(25); // 1Math.sign(0); // 0
Math.sign(-25); // -1
… and much more
https://github.com/lukehoban/es6features#math--number--string--array--object-apis
Useful links• http://www.2ality.com/2015/02/es6-classes-final.html
• http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html
• http://kangax.github.io/compat-table/es6/
• https://github.com/lukehoban/es6features
• http://es6-features.org/
• http://ilikekillnerds.com/2015/02/what-are-weakmaps-in-es6/