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