by Kiril Knysh
91%
|
85%
|
53%
|
79%
|
29%
|
53%
|
block-scoped
for (let i = 0; i < count; i++) {
...
}
//i is not defined here
if (value <= maxValue) {
let newValue = value * 0.1;
}
//newValue is not defined here
constrained by TDZ semantics
function execute() {
console.log(value);
var value = 10;
console.log(value);
...
}
function execute() {
console.log(value); //Uncaught ReferenceError: value is not defined
let value = 10;
console.log(value);
...
}
function execute() {
let value = 10;
console.log(value); //10
...
}
single-assignment
function execute() {
const value = 10;
...
value = 15; //Uncaught TypeError: Assignment to constant variable
}
function execute() {
const value = { tax: 10, mult: 0.4 };
...
value.tax = 15; //OK!
}
declared with `backticks`
`I am template`
can be multiline
`I am
template`
allow interpolation
const value = 10;
function getMult() { return 0.4; }
`Value is ${value};
Mult is ${getMult()};
2 + 2 = ${2 + 2}`
ES5
function createChannel(id) {
var channel = {
id: id,
toString: function() { return this.id; }
};
channel[Constants.KEY_1] = "Value 1";
channel[getKey()] = "Value 2";
return channel;
}
ES2015
function createChannel(id) {
return {
id,
toString() { return this.id + super.toString(); }, //id + [object Object]
[Constants.KEY_1]: "Value 1",
[getKey()]: "Value 2"
};
}
ES5
var id = channel.id;
var num = channel.num;
var url = channel.pictures[0] || 'default.png';
ES2015
const { id, num, pictures: [url='default.png'] } = channel;
works with arrays
const [zero, , two] = [0, 1, 2, 3, 4];
console.log(zero); //0
console.log(two); //2
swap values
[left, right] = [right, left];
in function params
function printChannel({ id, num }) {
console.log(`ID=${id}, NUM=${num}`);
}
printChannel(channel);
function printChannel({ id='', num=0 } = {}) {
console.log(`ID=${id}, NUM=${num}`); //ID=, NUM=0
}
printChannel();
spread
function getDistance(x1, y1, x2, y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}
const point1 = [10, 5];
const point2 = [12, 9];
getDistance(...point1, ...point2);
rest
function execute(fun, context, ...params) {
return fun.apply(context, params);
}
execute(Math.max, Math, 10, 20, 5); //20
const fetchChannels = (startIndex, count) => {
return CHANNELS.splice(startIndex, count);
}
shorthands
//no parenthesis for params, implicit return
channels.map(channel => channel.id);
//to return an object implicitly, wrap it in parenthesis
channels.map(channel => ({
channelId: channel.id,
poster: channel.pictures[0]
}));
//2 and more params
channels.map((channel, index) => {
const poster = channel.pictures[0] + `?index=${index}`;
return { channelId: channel.id, poster };
});
are bound to their lexical scope
const channel = {
pictures: ['https://...', 'https://...'],
size: { w: '300', h: '200' },
printPicturesUrl() {
this.pictures.forEach((url) => {
console.log(`${url}?w=${this.size.w}&h=${this.size.h}`);
});
}
}
don't have names, but
function mapChannels(channels) {
return channels.reduce((result, channel) => {
channel.pictures.forEach((picture) => {
//...
});
}, []);
}
class Animal {
constructor(name, color) {
this.name = name;
this.color = color;
}
//static function
static className() {
return 'Animal';
}
//getter property
get stringified() {
return `${this.name} - ${this.color}`;
}
}
inheritance
class Dog extends Animal {
constructor(name, color, birthDay) {
super(name, color);
this.birthDay = birthDay;
}
static className() {
return 'Dog';
}
get stringified() {
return `${super.stringified} : ${this.birthDay}`;
}
}
files that export an API
with strict mode by default
exports
default export
export default function(channel) {
return channel && channel.logo || null;
}
named export
export const LOGO_KEY = 'channel-logo-key-1';
multiple exports
function getName(channel) { return channel && channel.name || ''; }
const LOGO_KEY = 'channel-logo-key-1';
export { getName, LOGO_KEY };
export default function(channel) {
return channel && channel.logo || null;
}
imports
load module
import 'channels-helper';
import default as
export default function(channel) {
return channel && channel.logo || null;
}
import getChannelLogo from 'channels-helper';
import named exports
export const LOGO_KEY = 'channel-logo-key-1';
import { LOGO_KEY } from 'channels-helper';
import { LOGO_KEY as channelLogoKey } from 'channels-helper';
imports
mixed import
function getName(channel) { return channel && channel.name || ''; }
const LOGO_KEY = 'channel-logo-key-1';
export { getName, LOGO_KEY };
export default function(channel) {
return channel && channel.logo || null;
}
import getChannelLogo, { getName as getChannelName } from 'channels-helper';
import namespace
function getName(channel) { return channel && channel.name || ''; }
const LOGO_KEY = 'channel-logo-key-1';
export { getName, LOGO_KEY };
import * as ChannelsHelper from 'channels-helper';
const p = new Promise((resolve, reject) => {
//do some async work
//...
if (result) {
resolve(result);
} else {
reject(error);
}
});
follow Promises/A+ spec
p.then(
(result) => {
//handle success
},
(error) => {
//process error
}
);
support chaining
fetchChannels()
.then((channels) => {
return fetchEvents(channels);
}).then((events) => {
return processEvents(events);
}).catch((error) => {
log.error(error); //catches Promise reject + exceptions
});
static methods
//create resolved Promise
Promise.resolve(value);
//create rejected Promise
Promise.reject(error);
//wait for all Promises to be resolved or at least one rejected
Promise.all([fetchChannels(), fetchProfile()]);
//wait for the 1st resolved/rejected Promise
Promise.race([fetchChannels1(), fetchChannels2()]);
objects that know how to access items from a collection
implement the @@iterator method (property with a Symbol.iterator key)
const channels = {};
channels[Symbol.iterator] = function* () {
yield 'BBC';
yield 'MTV';
yield 'Fashion TV';
}
[...channels]; //['BBC', 'MTV', 'Fashion TV']
for (let channel of channels) { console.log(channel); }
//BBC
//MTV
//Fashion TV
special type of functions that work as a factory for iterators
function* getChannelsIterator() {
yield* ['BBC', 'MTV', 'Fashion TV'];
}
const channels = getChannelsIterator();
channels.next(); //{value: "BBC", done: false}
channels.next(); //{value: "MTV", done: false}
channels.next(); //{value: "Fashion TV", done: false}
channels.next(); //{value: undefined, done: true}
internal state
function* getUniqId() {
let current = 0;
while (true) {
let reset = yield current;
current = reset ? 0 : ++current;
}
}
const generator = getUniqId();
generator.next(); //{value: 0, done: false}
generator.next(); //{value: 1, done: false}
generator.next(); //{value: 2, done: false}
generator.next(true); //{value: 0, done: false}
generator.next(); //{value: 1, done: false}
const requestParams = { w: 300, h: 200 };
const response = fetch(requestParams);
const map = new Map([ ['key-1', 'value-1'], [requestParams, response] ]);
map.set('key-2', 'value-2');
map.get(requestParams) === response;
map.delete('key-1');
map.has('key-1') === false;
iterate
map.forEach((value, key) => { ... });
for (let [key, value] of map) { ... }
Array.from(map).forEach(([key, value], index) => { ... });
_.forEachRight([...map], ([key, value], index) => { ... });
const cache = new WeakMap();
cache.set(channel, getMetaData(channel));
cache.get(channel);
const set = new Set([1, 2, 3]);
set.size; //3
set.add(2);
set.size; //3
set.has(1) === true;
iterate
set.forEach((value) => { ... });
for (let value of set) { ... }
Array.from(set).forEach((value, index) => { ... });
_.forEachRight([...set], (value, index) => { ... });
const cache = new WeakSet();
cache.add(channel);
cache.has(channel) === true;
useful for interception, logging/profiling, data mocks, etc
const channel = { id: 'mtv', num: 12 };
const handler = {
get: (receiver, name) => {
if (name === 'num') {
return `${receiver.id} - ${receiver.num}`;
}
return receiver[name];
}
};
const prox = new Proxy(channel, handler);
prox.id === 'mtv';
prox.num === 'mtv - 12';
freeze objects
const channel = { id: 'mtv', num: 12 };
function preventChange() { throw new Error('Object is frozen'); }
const handler = {
set: preventChange,
defineProperty: preventChange,
deleteProperty: preventChange,
preventExtensions: preventChange,
setPrototypeOf: preventChange
};
const prox = new Proxy(channel, handler);
prox.id = 'bbc'; //Uncaught Error: Object is frozen