On Github PaquitoSoft / es-2015-talk
Current support status: Kangax ES* table
HTML 5 first release 2014/10/28Best results when used with Webpack.
Allows to define a scoped block variable
Allows to declare non updatable valuesBeware of objects and arrays: Object.freeze/Object.seal are your friends here.
configureEvents() { for (let key in this.domEvents) { let tokens = key.split('|'); dom.addEvent( this.$el, tokens[0], tokens[1] || undefined, this[this.domEvents[key]].bind(this) ); } if (this.defaultNavigation) { dom.addEvent(this.$el, 'click', 'a', this.navTo); } }
const PODCASTS_DATASOURCE_URL = 'https://itunes.apple.com/us/rss/toppodcasts/limit=100/genre=1310/json'; const PODCAST_CACHE_PREFIX = 'podcast-data_'; const PODCASTS_LIST_CACHE_TTL = 1440; // minutes (one day) const CONFIG = { defaultTTl: 1440 }; console.log(CONFIG); // --> { defaultTTl: 1440 } CONFIG.defaultTtl = 10; console.log(CONFIG); // --> { defaultTTl: 10 } const CONFIG = Object.freeze({ defaultTtl: 1440 }); console.log(CONFIG); // --> { defaultTTl: 1440 } CONFIG.defaultTtl = 10; console.log(CONFIG); // --> { defaultTTl: 1440 }If you use freeze you don't need const, it's useless. Arrays can be freezed so you cannot assign new values. Adding, removing throws error. Object.seal() also prevent new properties to be added to the object.
processRoute(path, state = {}) { ... if (routeConfig) { try { routeConfig.handler({ url: _path, params: routeConfig.path.match(_path), state }) .then(this.navigate.bind(this)) .catch((navError) => { console.error('RouterEngine::navigate# Error navigating:', navError); this.trigger(RouterEvents.navigationEnd); this.trigger(RouterEvents.navigationError, navError); }); } catch (err) { ...Parenthesis are optional if function has only one parameter
static findById(podcastId) { let cacheKey = PODCAST_CACHE_PREFIX + podcastId, podcast = lscache.get(cacheKey); if (podcast) { return Promise.resolve(podcast); } else { return new Promise(function(resolve, reject) { getPodcastLite(podcastId) .then(fetchPodcastFeedUrl) .then(fetchPodcastEpisodes) .then(function(data) { lscache.set(cacheKey, data, PODCAST_DETAIL_CACHE_TTL); resolve(data); }) .catch(reject); }); } }
{ path: '/podcast/:podcastId', handler: function podcastDetailHandler(context) { return new Promise((resolve, reject) => { PodcastModel.findById(context.params.namedParams.podcastId) .then(function(data) { resolve({ Controller:PodcastPageController, data: { podcast: data } }); }) .catch(reject); }); } }
trigger(eventName, data = {}) { let listeners = this.eventsRegistry[eventName] || []; for (let listener of listeners) { try { listener.call(this, data); } catch (e) { console.warn(`Error in event (${eventName}): ${e.message}`); } } }
function fetchPodcastFeedUrl(podcast) { return new Promise(function(resolve, reject) { ajax.getJsonp(`${PODCAST_ID_DATASOURCE_URL}?id=podcast.id`) .then(function(data) { if (data.results.length) { podcast.feedUrl = data.results[0].feedUrl; resolve(podcast); } else { reject(new Error('No feed Url found for podcast: ' + podcast.id)); } }) .catch(reject); }); } function foo() { return 42; } console.log(`The meaning of life is: ${foo()}`);
// Code from MDN var a = 5; var b = 10; function tag(strings, ...values) { console.log(strings[0]); // "Hello " console.log(strings[1]); // " world " console.log(values[0]); // 15 console.log(values[1]); // 50 return "Bazinga!"; } tag`Hello ${ a + b } world ${ a * b}`; // "Bazinga!"
class BaseController { constructor(options = {}) { this.data = options.data; this.template = options.template; this.partials = options.partials; this.domEvents = options.domEvents; this.defaultNavigation = (typeof options.defaultNavigation === 'undefined') ? true : options.defaultNavigation; // https://developer.mozilla.org/en-US/docs/Web/API/DOMParser // http://caniuse.com/#feat=xml-serializer this.domParser = new DOMParser(); } ...
class EpisodeController extends BaseController { constructor(data) { super({ data, template: EpisodePageTemplate, partials: { podcastSidebar: PodcastSidebarPartialTemplate } }); } }Don't forget to mention 'static' functions (promises code-1)
class Foo extends Bar { constructor() { this._degrees = 0; } sayHi(name) { super.sayHi(`Awesome ${name}`); } get degrees() { return this._degrees; } set (value) this._degrees = (value * 2); } } let bar = new Foo(); console.log(bar.degrees); // -> 0 bar.degrees = 15; console.log(bar.degrees); // -> 30
// plugins/dom.js function matches($el, selector) { let _matches = $el.matches || $el.msMatchesSelector; return _matches.call($el, selector); } export function findEl(selector, container) { return (container || document).querySelector(selector); } // controllers/home-controller.js import * as dom from '../plugins/dom'; update() { let $updatedEl = this.render(), $prevPodcasts = dom.findEl('.podcasts', this.$el); dom.findEl('.badge', this.$el).innerHTML = this.data.podcasts.length; $prevPodcasts.parentNode.replaceChild( dom.findEl('.podcasts', $updatedEl), $prevPodcasts ); }
// models/podcast.js class Podcast { ... } export default Podcast; // config/routes.js import PodcastModel from '../models/podcast'; { path: '/', handler: function homePageController() { return new Promise((resolve, reject) => { PodcastModel.findAll() .then(function(data) { ... }) .catch(reject); }); } }
// plugins/router.js export let RouterEvents = Object.freeze({ navigationStart: 'navigationStart', navigationEnd: 'navigationEnd', navigationError: 'navigationError', routeNotFound: 'routeNotFound' }); export class RouterEngine extends EventsEmitter { static navTo(path, state = {}) { window.history.pushState(state, '', `#${path}`); window.dispatchEvent(new PopStateEvent('popstate', { state })); } ... } // controllers/base-controller.js import { RouterEngine } from '../plugins/router'; navTo(event, $target) { event.preventDefault(); RouterEngine.navTo($target.getAttribute('href')); }
constructor(data) { super({ data, template: PodcastPageTemplate, partials: { podcastSidebar: PodcastSidebarPartialTemplate }, defaultNavigation: false, domEvents: { 'click|.podcast-sidebar a': 'navTo', 'click|.podcast-episodes a': 'navToEpisode' } }); } let obj = { name: 'Luke', sayHi() { return `Greetings from ${this.name}`; } };
Array.from converts array-like objects into truly arrays
export function findEls(selector, container) { return Array.from((container || document).querySelectorAll(selector)); } let productsImages = findEls('img.product-detail').map(($product) => { return $product.getAttribute('src'); }); // Also (only in Firefox) for (let el of (container || document).querySelectorAll(selector)) { console.log(el); }
// Router export let RouterEvents = {} export class RouterEngine extends EventsEmitter {} // BaseController import { RouterEngine } from '../plugins/router'; // Arrays let arr = ['Rollo', 'Tomassi', 46]; let [name, surname, age] = arr; // Defaults var { x = 3 } = {}; console.log(x); // 3
var MyClass = (function() { // module scoped symbol var key = Symbol("key"); function MyClass(privateData) { this[key] = privateData; } MyClass.prototype = { doStuff: function() { return this[key]; } }; return MyClass; })(); var c = new MyClass("hello") console.log(c["key"]); // undefined console.log(c.doStuff()); // "hello" console.log(c[Object.getOwnPropertySymbols(c)[0]]); // "hello"
let arr = [3, 5, 7]; arr.foo = "hello"; for (let i in arr) { console.log(i); // logs "3", "5", "7", "foo" } for (let i of arr) { console.log(i); // logs "3", "5", "7" }
function sum(base, ...numbers) { result = base; numbers.forEach(num => { result += num: }); return result; } let x = 10; console.log(sum(x, 2, 4, 5, 8)); // 29 // OLD var args = Array.prototype.slice.call(arguments);
function sum(a, b, c) { return a + b + c; } let args = [2, 5, 7]; // sum.apply(null, args); sum(...args); let spans = document.querySelectorAll('span'); spans.forEach((el) => console.log(el.tagName)); // ---> ERROR [...spans].forEach((el) => console.log(el.tagName)); // ---> "SPAN", "SPAN",...
let person = new Observable({ name: 'Rollo Tomassi', age: 47 }); person.onPropertyChanged(function(property, prev, current) { console.info(`Changing property: ${property}...`); console.info(`From (${prev}) to (${current})`); }); person.age = 48; person.age++;
function Observable(target) { let observableRegistry = []; function triggerPropertyChanged(property, previousValue, newValue) { observableRegistry.forEach(callback => { callback.call(null, property, previousValue, newValue); }); } let proxy = new Proxy(target, { set: function(object, property, value, proxy) { let previousValue = object[property]; object[property] = value; if ('onPropertyChanged' !== property) { triggerPropertyChanged(property, previousValue, value); } return true; } }); proxy.onPropertyChanged = function(callback) { observableRegistry.push(callback); }; return proxy; }