2. Зачем уметь варить JS ?!
Большие веб
приложения
Настольные
приложения
Мобильные
приложения
Jeff Atwood (2007): any application that can be written in
JavaScript, will eventually be written in JavaScript
3. Часть 1. Парадигмы программирования
1.Популярные парадигмы
2.Процедурный подход (ПП)
3.Функциональное программирование (ФП)
a.Функция: ФП vs ПП
b.Возможности ФП
4.Объектно ориентированный подход
a."Как это было вчера и будет завтра" –
эмуляция классов, прототипы, ES6
b."Как это можно делать сегодня"
4. Часть 2. Шаблоны проектирования
1.Что такое шаблон проектирования ?
2.Пространства имён
3.Классические шаблоны:
a.Порождающие - Singleton
b.Поведенческие - Observer
4.MV* шаблоны - современный подход к разработке
больших приложений
7. Ч1. Процедурное программирование (ПП)
Программирование, при
котором последовательно
выполняемые операторы можно
собрать в подпрограммы
(функции, процедуры), то есть
более крупные целостные
единицы кода, с помощью
механизмов самого языка.
8. Ч1. ПП - Пример кода
var allowedImgSize = 3000000;
var allowedImgNumber = 10;
var fileCountReaded = 0;
var fileCountUploaded = 0;
(function($){
$(document).ready(function(){
$( "#from-date" ).datepicker({
minDate: 11,
showOn: "button",
....
Глобальные переменные –
к чему относятся, откуда
вызываются ?
9. Ч1. ПП - Почему этот подход плох ?!
С ростом приложений, в отсутствии жёстких
правил структурирования кода, мы получаем
большой набор плохо поддерживаемого кода
- Spaghetti code
Организация кода очень напоминает
организацию «Кхаласара» – племя
кочевников: никакой инфраструктуры, почти
нет правил, всё – общее. Также кхаласары
могут сражаться друг с другом, при этом члены
побежденного кхаласара присоединяются к
победившему.
10. Ч1. ПП - Проблемы Spaghetti кода
Плохо тестируемый
Плохо читаемый
Плохо расширяемый
Создаёт предпосылки для
возникновения ошибок из-за
большого взаимодействия с
внешней средой
ПП в чистом виде – это подход новичков
11. Ч1. ФП – Первое решение
Функциональное программирование (ФП) —
подход к программированию, в котором функции
являются главным инструментом работы: они
считают результат, они могут также передаваться
в качестве аргументов и возвращаться в качестве
результатов.
12. Ч1. ПП vs ФП
Функция в ПП Функция в ФП
1. Не изменяет входные данные
2. Не обладает побочными
эффектами
3. Является строго
детерминированной
4. Не осуществляет операций
ввода, вывода
1. Изменяет входные данные
2. Может изменять среду в
которой исполняется
3. Результат не всегда
предсказуем
4. Содержит alert, prompt
Чистая функция
13. Ч1. ФП - Возможности ФП в JS
Фильтры и Конвейер (pipe)
Мемоизация
Каррирование
16. Ч1. ФП - Фильтры и Конвейер
Функциональный подход
var filteredChildren = children
.filter(function (x) {
return x.age % 3 == 0;
})
.map(function (x) { return x.Name;})
.sort();
Процедурный подход
var filteredChildren = [];
for (var i in children) {
if (children[i].age % 3 == 0) {
filteredChildren.
push(children[i].Name);
}
}
filteredChildren.sort();
17. Ч1. ФП - Фильтры и Конвейер
1. Улучшают читаемость кода
2. Уменьшают количество переменных
3. Сводят к минимуму количество условных операторов
18. Ч1. ФП - Мемоизация
Мемоизация — сохранение результатов выполнения
функций для предотвращения повторных вычислений.
Плюсы: увеличение скорости выполнения программы
Минусы: дополнительный расход памяти
19. Ч1. ФП - Мемоизация
На островах Вестероса, учёные мужи – Маэстры, нашли
удивительную закономерность чисел, которая часто
встречается в природе. Она начинается с 0,1, а каждое
следующее число получается суммированием двух
предыдущих. По одним лишь им известным причинам,
зовут они их – числа Фибоначчи
20. Ч1. ФП - Мемоизация
«Наивный» подход
При n = 40, 331 160 281 - вызовов
function fibonacci(n) {
if (n == 0 || n == 1) {
return n;
}
return fibonacci(n-1) + fibonacci(n-2);
}
Использование мемоизации
При n = 40, 79 вызовов
var fibonacci = (function () {
var memo = {};
function f(n) {
var value;
if (n in memo) {
value = memo[n];
} else {
if (n == 0 || n == 1) value = n;
else value = f(n - 1) + f(n-2);
memo[n] = value;
}
return value;
}
return f;})();
21. Ч1. ФП - Каррирование
Преобразование функции от многих аргументов
в функцию, берущую свои аргументы по одному
(названо в честь Хаскелла Карри)
function sum(a, b) { }
sum(5,6) sum(5)(6)
22. Ч1. ФП - Каррирование
lodash - библиотека с огромным количеством
инструментов для работы с массивами, коллекциями,
объектами, функциями.
https://lodash.com/
23. Ч1. ФП - Каррирование
var add = function (a, b, c, d) {
return a + b + c + d;
}
var inc = _.curry(add);
console.log(inc(6, 7, 8, 9));
console.log(inc(6)(7)(8, 9));
var inc2 = inc(6);
var inc3 = inc2(7);
var inc4 = inc3(8);
console.log(inc4(9));
24. Ч1. ФП - Зачем использовать ?
Функциональное П
Лёгкое и эффективное unit тестирование
Хорошо читаемый
Минимальный внешний эффект
Плохо расширяемый
Процедурное П
Плохо тестируемый
Плохо читаемый
Плохо расширяемый
Создаёт предпосылки для возникновения
ошибок из-за большого взаимодействия с
внешней средой
26. Ч1. ООП - Особенности в JS (ES5)
Нет классов
Нет интерфейсов
Используется функция конструктор для
инстанциирования объектов
Наследование основано на прототипах
27. Как это было вчера ES5
function Warrior(strength) {
this.strength = strength;
this.say = function () {
// code
}
}
Warrior.prototype.kick=function(){
return this.strength;
}
Как это будет завтра ES6
class Warrior {
constructor(strength) {
// code
}
kick() {
console.log("My strength is: "
+ this.strength);
}
say(){}
}
Ч1. ООП – Вчера vs Завтра
var snow = new Warrior(10);
snow.say();
28. Как это было вчера ES5
function Knight(strength) {
this.strength = 2 * strength;
}
Knight.prototype =
Object.create(Warrior.prototype);
Knight.prototype.kick = function(){
Warrior.prototype.kick.call(this);
console.log("I am knight. I have
double strength");
}
Как это будет завтра ES6
class Knight extends Warrior {
constructor(strength) {
super(2 * strength);
}
kick() {
super.kick();
console.log("I am knight. I
have double strength");
}
}
Ч1. ООП – Вчера vs Завтра
var jaime = new Knight(10);
jaime.kick();
29. Ч1. ООП – Как это можно делать сегодня
TypeScript
1. Компилируется в JS ( Разные версии)
2. Схожий синтаксис с ES6
3. Строгая типизация, интерфейсы, модули
31. Ч2. Шаблоны проектирования
Шаблон проектирования или паттерн (англ. design pattern)
в разработке программного обеспечения —
повторимая архитектурная конструкция, представляющая собой
решение проблемы проектирования в рамках некоторого часто
возникающего контекста.
Содержит 23 шаблона проектирования
Порождающие – 5
Структурные – 7
Поведенческие – 11
Примеры написаны на С++, Smalltalk
33. Ч2. Пространства имён
Как известно в Вестерос входит 7
королевств, которые подчиняются
королю. Каждым королевством
управляет лорд, а само оно делится на
ещё меньшие области. Каждая
область имеет обычно главный замок
и близлежищие деревеньки, в
которых живут люди.
То есть, можно сказать, что Север
входит в Вестерос, а Винтерфелл
соотвествено в Север.
34. Ч2. Пространства имён - реализация
var vesteros = vesteros || {};
vesteros.namespace = function (ns_string) {
var parts = ns_string.split('.'),
parent = vesteros, i;
// отбросить начальный префикс – имя глобального
объекта
if (parts[0] === 'vesteros') {
parts = parts.slice(1);
}
for (i = 0; i < parts.length; i += 1) {
// создать свойство, если оно отсутствует
if (typeof parent[parts[i]] === 'undefined') {
parent[parts[i]] = {};
}
parent = parent[parts[i]];
}
return parent;
};
объект
35. Ч2. Пространства имён - применение
// присваивание возвращаемое значение локальной переменной
var greenvale = vesteros.namespace('vesteros.dorn.greenvale');
greenvale === vesteros.dorn.greenvale; // true
// можно опустить начальный префикс `vesteros`
vesteros.namespace('north.winterfell');
36. Ч2. Порождающие шаблоны - Singleton
Шаблон проектирования, гарантирующий, что в однопоточном
приложении будет единственный экземпляр класса с глобальной
точкой доступа
Области применения: модули в Node.js, сервисы в Symfony (PHP),
Bean в Spring (Java)(По умолчанию)
37. Ч2. Порождающие шаблоны - Singleton
На крайнем севере Вестероса, за восемь тысяч лет до
начала войны пяти королей, в эпоху героев, была построена
огромная стена, для того, чтобы защищать Вестерос от
белых ходоков.
38. Java
public class Wall {
private static Wall instance;
private Wall () {}
public static Wall getInstance() {
if (instance == null) {
instance = new Wall();
}
return instance;
}
}
JS
function Wall() {
if (Wall.instance) {
return Wall.instance;
}
Wall.instance = this;
}
Wall.getInstance = function () {
return Wall.instance;
}
Ч2. Порождающие шаблоны - Singleton
Wall.instance = 5;
39. Ч2. Порождающие шаблоны - Singleton
var Wall = (function () {
var instance = null;
function Wall() {
if (instance){
return instance;
}
instance = this;
}
Wall.getInstance = function () {
if (instance) {
instance = new Wall();
}
return instance;
};
return Wall;
})();
Анонимная функция
Вызов
40. Ч2. Поведенческие шаблоны
Шаблоны проектирования, определяющие алгоритмы и способы
реализации взаимодействия различных объектов и классов.
Отлично реализуется в JS, благодаря возможности сохранять
функции в структурах данных.
41. Ч2. Поведенческие шаблоны - Observer
Шаблон проектирования, который помогает определить
зависимость типа «один ко многим» между объектами таким
образом, что при изменении состояния одного объекта все
зависящие от него оповещаются об этом событии
42. Ч2. Поведенческие шаблоны - Observer
Королевский двор Вестероса – это место изощрённых интриг и
коварства. Действующие лица очень активно используют шпионов,
причём часто, один и тот же шпион работает на нескольких
представителей двора, поэтому, как только шпион что-то узнаёт, он
должен сразу доложить всем информацию.
43. Ч2. Поведенческие шаблоны - Observer
var Spy = (function () {
function Spy() {
this._partiesToNotify = [];
}
Spy.prototype.subscribe = function (subscriberFn) {
this._partiesToNotify.push(subscriberFn);
};
Spy.prototype.whisper = function (event) {
for (var i = 0; i < this._partiesToNotify.length; i++) {
this._partiesToNotify[i](event);
}
};
return Spy;
})();
Хранитель подписчиков
44. Ч2. Поведенческие шаблоны - Observer
var Player = (function () {
function Player() {
}
Player.prototype.listen = function(info) {
//perform some action
};
return Player;
})();
var s = new Spy();
var p = new Player();
s.subscribe(p.listen); //p is now a subscriber
s.whisper(12); //s will notify all subscribers
51. Вывод
JS - это гибкий язык программирования, который позволяет под
нужные задачи использовать разные подходы
Способов решения задачи огромное количество, самое сложное –
выбрать правильный. Что вам и желаю !
53. Ч1. ФП - «Ленивая» инициализация
Приём в программировании, когда некоторая ресурсоёмкая
операция выполняется непосредственно перед тем, как будет
использован её результат. Таким образом, инициализация
выполняется «по требованию», а не заблаговременно.
Плюсы: Инициализация выполняется только в тех случаях, когда
она действительно необходима
Минусы: Невозможно явным образом задать порядок
инициализации объектов
54. Ч1. ФП - «Ленивая» инициализация
Пекарня в Вестеросе выпекает отличный хлеб. Они получают
заказы на разный вид хлеба, но сразу не пекут. Так как
создание объекта “Bread” – это дорогостоящая операция,
поэтому они стараются отложить эту работу, пока кто-нибудь
действительно не придёт за хлебом.
56. Ч1. ФП - «Ленивая» инициализация
Создаём объект “Bakery”. Он будет принимать заказы на разный вид хлеба.
var Bakery = (function () {
function Bakery() {
this.requiredBreads = [];
}
Bakery.prototype.orderBreadType = function (breadType) {
this.requiredBreads.push(breadType);
};
Теперь у нас есть возможность быстро принимать заказы
не тратя время на их реализацию.
57. Bakery.prototype.buy = function (breadType) {
// create and return
};
var bakery = new Bakery();
bakery.orderBreadType("Brioche");
bakery.orderBreadType("Anadama bread");
bakery.orderBreadType("Chapati");
bakery.orderBreadType("Focaccia");
Ч1. ФП - «Ленивая» инициализация
bakery.buy("Chapati")
;
Инициализация
58. Прил 1. Каррирование – имплементация
function curry(fx) {
var arity = fx.length;
return function f1() {
var args = Array.prototype.slice.call(arguments, 0);
if (args.length >= arity) {
return fx.apply(null, args);
}
else {
return function f2() {
var args2 =
Array.prototype.slice.call(arguments, 0);
return f1.apply(null, args.concat(args2));
}
}
};
}
61. Прил 1. ФП – Каррирование - применение
rende
r Curry renderC
render1 render2
62. Прил 1. ФП – Каррирование - применение
function getData(renderFn) {
// get data
var data = 5;
renderFn(data);
}
function renderComplicate(flag,
data) {
if (flag) {
console.log(2 * data);
} else {
console.log(3 * data);
}
}
var r = _.curry(renderComplicate);
var r1 = r(true);
var r2 = r(false);
getData(r1); // 10
getData(r2); // 15
63. Ч2. Шаблон модуль
var Dragon = (function () {
function Dragon(strength) {
this.strength = strength;
}
Dragon.prototype.burn = function () {
return "Dragon is close...";
};
return Dragon;
}());
Анонимная функция
Вызов
64. Ч2. Структурные шаблоны
Шаблоны проектирования, в которых рассматривается вопрос о
том, как из множества классов или множества объектов
образуются более крупные или изменённые структуры.
65. Ч2. Структурные шаблоны
Широко используется агрегация и
композиция
JS – язык с динамической типизацией
Удобная реализация
66. Ч2. Структурные шаблоны - Decorator
Структурный шаблон проектирования, предназначенный для
динамического подключения дополнительного поведения
к объекту. Шаблон Декоратор предоставляет гибкую альтернативу
практике создания подклассов с целью расширения
функциональности.
67. Ч2. Структурные шаблоны - Decorator
Броня, которую рыцари Вестероса носят, является очень
конфигурируемой и «настраивается» под любые нужды и размер
кошелька заказчика. Она может быть кольчужной, иметь
вплетения, сделанные из медных колец, позолоченные. Так же
могут быть разные наколенники, и разные вставки в шлем.
Вариантов очень много, особенно для кодинга !
68. Ч2. Структурные шаблоны - Adapter
Структурный шаблон проектирования, предназначенный для
организации использования функций объекта, недоступного для
модификации, через специально созданный интерфейс.
69. Ч2. Структурные шаблоны - Decorator
var BasicArmor = (function(){
function BA () {}
BA.prototype.damage=function(hit){
return hit.s / 1.5;
};
return BA;
})();
var ChainMail = (function () {
function CM(ba) {
this.bArmor = ba;
}
CM.prototype.damage=function(hit) {
hit.s *= 0.8;
return this.bArmor.damage(hit);
};
return CM;
})();
var armor = new ChainMail(new BasicArmor());
70. Ч2. Структурные шаблоны - Adapter
В Вестеросе очень опасно путешествовать. С лёгкостью можно попасть в руки
к разбойникам или заблудиться, поэтому часто, люди у которых есть деньги
пользуются кораблём. Однако кораблём мы управлять не умеем, в отличие от
верблюда.
interface Ship{
SetRudderAngleTo(angle);
SetSailConfiguration(configuration);
SetSailAngle(sailId, sailAngle);
GetCurrentBearing();
GetCurrentSpeedEstimate();
ShiftCrewWeightTo(weightToShift, locationId);
}
interface Camel{
TurnLeft();
TurnRight();
GoForward();
}
71. Ч2. Структурные шаблоны - Adapter
var Camel = (function () {
function Camel() {
this._ship = new Ship();
}
Camel.prototype.TurnLeft = function () {
this._ship.SetRudderAngleTo(-30);
this._ship.SetSailAngle(3, 12);
};
Camel.prototype.TurnRight = function () {
this._ship.SetRudderAngleTo(30);
this._ship.SetSailAngle(5, -9);
};
Camel.prototype.GoForward= function () {
//do something else to the _ship
};
return Camel;
})();
var camel = new Camel();
camel.GoForward();
camel.TurnLeft();
72. Dirty checking
Через каждый интервал времени,
проверяются все поля во VM, на
предмет их изменения, если они
были изменены, то обновляется
Представление. В Представлении на
всех контролах сидят слушатели.
Контейнерный объект
Пример: Библиотека - Knockout.js
function CreateCastleVModel(name) {
this.name = ko.observable(name);
}
var model = new CreateCastleVModel();
model.name("Winterfell"); //set
model.name(); //get
Ч2. MVVM – варианты реализации
Использует: Angular Использует: Backbone, Ember