Обычно я нахожу обсуждение шаблонов проектирования немного сухим, но при тестировании новых библиотек Javascript я наткнулся на некоторые интересные тактики. Шаблоны объектно-ориентированного дизайна типично не идеально подходят для Javascript, учитывая его нетипизированный характер. Язык больше подходит для мощных функциональных методов программирования. Я считаю, что изучение библиотек особенно полезно, поскольку в учебных томах часто отсутствует контекст того, как можно практически использовать различные структуры данных.
ExtJS — объекты конфигурации
ExtJS — это инфраструктура Javascript для многофункциональных пользовательских интерфейсов в стиле рабочего стола. Библиотека предоставляет множество элементов управления: сетки, средства выбора даты, диаграммы и т. Д. Когда вы хотите создать объект, вы вызываете конструктор или предоставляете имя типа («xtype»), которое Ext использует для поиска зарегистрированных типов.
Когда вы создаете объект, вы можете предоставить объект конфигурации, который позволит вам контролировать конечный результат. Под капотом Ext создает пустой объект, добавляет функции и значения из определения типа, а затем использует Javascript-метод «apply» для объединения ваших данных с базовым объектом.
Ext.create('Ext.panel.Panel', { title: 'Panel with ButtonGroup', width: 300, height:200, renderTo: document.body, bodyPadding: 10, html: 'HTML Panel Content', tbar: [{ xtype: 'buttongroup', columns: 3, title: 'Clipboard', items: [{ text: 'Paste', scale: 'large', rowspan: 3, iconCls: 'add', iconAlign: 'top', cls: 'btn-as-arrow' }] }] });
Эти объекты конфигурации обманчиво просты и внешне не относятся к обсуждению функционального программирования. Поскольку этот шаблон позволяет вам одновременно копировать и обновлять любую часть объекта, вы достаточно близки к работе с неизменяемыми объектами (хотя на практике я не видел, чтобы кто-нибудь так относился к объектам Ext).
Объекты Config предназначены не только для задания значений по умолчанию — Ext использует их для поддержки иерархий объектов, статических методов, миксинов и множественного наследования. Это также обеспечивает тривиальные конструкторы копирования, анализ «что если» и, в некоторых случаях, код, который самодокументируется естественным образом.
Lunr.js — сериализация
Lunr.js — это библиотека Javascript для построения полнотекстовых индексов. Он реализует интересное расширение предыдущей концепции — он предоставляет API для получения сериализуемого объекта. Это нециклический объект, очищенный от функций для сериализации / десериализации.
var serializedIndex = JSON.stringify(index1.toJSON()) var deserializedIndex = JSON.parse(serializedIndex) var index2 = lunr.Index.load(deserializedIndex)
После создания этот объект можно использовать так же, как объект конфигурации Ext, для создания нового полнотекстового индекса. Это упрощает передачу данных из одного приложения в другое (от поискового индекса до задания сокращения карты, записи CouchDB или компонента JAX-RS в Java)
Pdf.js — Обещания
PDF.js — это проект Firefox Labs, предназначенный полностью для рендеринга PDF в Javascript + Canvas. Процесс рендеринга интенсивно использует шаблон проектирования под названием Promises.
Я видел Promises в Scala, но никогда не задумывался над тем, как они были реализованы. PDF.js не первая или самая полная реализация, но отличная демонстрация того, где они полезны. Этот асинхронный шаблон подходит для рендеринга — вы можете выполнять различные операции рисования параллельно, например, для рендеринга каждой страницы PDF в отдельном потоке.
Обещания — это объекты, представляющие будущее состояние, позволяющие вам писать код, который работает с результатами незавершенного асинхронного вызова — если вы также можете связать обработку ошибок с ошибками. Идеальные реализации также позволяют связывать обещания. Это реализуется с помощью объектов, которые хранят обратные вызовы, которые используются, когда Promise готов:
var pdf = PDFJS.getDocument('42.pdf'); pdf.then(function(pdf) { var maxPages = pdf.pdfInfo.numPages; for (var j = 1; j <= maxPages; j++) { var page = pdf.getPage(j); var processPage = function processPage(pageData) { ... } page.then(processPage); } });
D3 — продолжения
D3 — это библиотека визуализации Javascript, которая широко использует вложенные замыкания, что дает впечатляющий эффект. Конструктивно код похож на Promises, но намного чище. Это обеспечивает возможность асинхронного кодирования (например, в анимации). В отличие от Promises, это приводит к гораздо более плавному сочетанию синхронного и асинхронного кода, без вложенного ада обратного вызова.
Каждый вызов функции создает новый объект, закрытый вокруг старого объекта. Поскольку значения представляют собой серию замыканий, их не нужно оценивать до конца. Единственным недостатком этого подхода является то, что реверс-инжиниринг сложнее, чем когда-либо, как ExtJS.
По сути, это то же самое, что функциональные списки в чисто функциональных структурах данных Окасаки .
Объекты предоставляют некоторые основные операции со списком, например:
concat, each, every, filter, forEach, indexOf, insert, join, map, lastIndexOf, order, pop, push, reduce, reduceRight, remove, reverse, shift, slice, some, sort, splice
Они также предоставляют некоторые методы манипулирования DOM:
append, attr, data, node, transition, select, selectAll, style, text
Эти методы также обычно принимают значения или обратные вызовы, мощную модель для настройки поведения.
svg = d3.select("body").append("svg"); svg.attr("id", name) .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); ... bar.data(histo) .transition() .delay(1000) .duration(1000);