Marek Fojtl , programátor senior UI Vylaďte si aplikaci! Návrhové vzory v JS www.seznam.cz Co po dnešku budu vědět? • co je to Immediately-invoked function expression a jaké je její použití • jak vytvářet objekty, realizovat dědičnost a vytvořit singleton • co je to ES6 a jak řeší absenci klíčového slova class v JS • jak řešit implementační rozdíly mezi prohlížeči za pomocí polyfillů • jak se vyhnout callback hell • jak zkrotit asynchronní kód • MVC a jeho zástupci Immediatelyinvoked function expression www.seznam.cz Nejčastější zápis • globální prostor DOMu se zanáší různými atributy • můžete přepsat atribut někoho jiného, který se později bude někde používat • obtížnější ladění chyb www.seznam.cz Nyní trochu lépe www.seznam.cz A nejlépe Objekty Konstrukční funkce Dědičnost Singleton www.seznam.cz Sestavit strom, zplodit objekt? • objekty lze vytvořit třemi způsoby: var obj1 = new Object(); var obj2 = {}; var obj3 = Object.create(Object.prototype); console.log(obj1 instanceof Object); // true console.log(obj2 instanceof Object); // true console.log(obj3 instanceof Object); // true • v JS je vše objekt • všechny objekty jsou potomky objektu Object • všechny objekty dědí základní metody a atributy z Object.prototype www.seznam.cz Class? To neznám! … Zatím. var Person = function(name) { this.name = name; }; Person.prototype.getName = function() { return name; }; var person = new Person("John Doe"); console.log(person.getName()); // "John Doe” • v JS se pro vytváření tříd (vzorů) používají konstrukční funkce a prototypy • konstrukční funkci voláme s operátorem new www.seznam.cz Zajímavost - simulace new // nasledujici kod popisuje temer to stejne, co se deje, kdyz se pouzije operator new function SimulateNew(func, params) { // vytvori se prazdny objekt var o = {}; // skryta vlastnost __proto__ zacne ukazovat na prototype funkce o.__proto__ = func.prototype; // zavolame konstrukcni funkci v kontextu nove vytvoreneho objektu func.apply(o, params); // vratime vytvoreny objekt return o; } // misto var person = new Person("John Doe"); pak lze napsat jako: var person = SimulateNew(Person, ["John Doe"]); console.log(person instanceof Person); // true www.seznam.cz Dědičnost var Person = function(name) { this.name = name; }; Person.prototype.getName = function() { return name; }; var Man = function(name) { // zavolame kons. funkci rodice v kontextu podedene tridy Person.apply(this, arguments); }; // naklonujeme metody a atributy z Person do Man Man.prototype = Object.create(Person.prototype); var man = new Man("Marek"); console.log(man.getName()); // Marek console.log(man instanceof Person && man instanceof Man); // true www.seznam.cz Singleton (function(win) { var instance = null; var App = function() { throw new Error("Can not call singleton with new!"); }; App.getInstance = function() { if (instance) { return instance; } instance = Object.create(App.prototype); instance.init(); return instance; }; App.prototype.init = function() { this.inited = true; }; win.App = App; })(window); ECMAScript 6 www.seznam.cz Co je to ECMAScript? • dále jen ES • skriptovací jazyk normovaný neziskovou organizací ECMA International • autoři interpreterů jazyka Javascript z něj vychází a při implementaci se řídí jeho specifikací • v moderních prohlížečích je momentálně implementován převážně ES5.1 • připravuje se ES6, která zejména přidává podporu zápisu pro psaní tříd a modulů www.seznam.cz ES6 Classes class Person { constructor(name) { this.name = name; } getName() { return this.name; } } class Man extends Person { constructor() { super(); } } www.seznam.cz Lze to použít již nyní? • ANO! • podobně jako na CoffeScript, TypeScript, LiveScript, … existuje i na ES6 transpiler pro překlad do ES5 kódu, kterému dnešní prohlížeče rozumí • https://github.com/google/traceur-compiler Polyfilly www.seznam.cz Prohlížeč mě nezná! ! • polyfill v JS je doplnění standardizované funkcionality (nebo API), kterou prohlížeč sám nemá • na rozdíl od abstrakce (viz např. $.bind("…")) pak může uživatelův kód používat standardní API a nestarat se o podporu prohlížečů či proprietární rozhraní • implementace polyfillu se řídí striktně specifikací, neměly by se do něj přidávat vlastní funkcionalita nebo vylepšení www.seznam.cz Příklad if (!Array.prototype.forEach) { Array.prototype.forEach = function(cb, _this) { var len = this.length; for (var i=0;i