Javascript
Статистика
Reklama 2Under.ru
кино, фильмы, видео
музыка и MP3
авто и мото
знакомства
заработок в сети
игры
форекс, forex
женские сайты
для взрослых
строительство и ремонт
недвижимость
бытовая техника
здоровье и медицина
красота, косметика
работа, вакансии, резюме
животные и растения
детские товары
знакомства для интима
софт
развлечения
одежда и обувь
туризм и отдых
мебель, интерьер
компьютеры и оргтехника
реклама и интернет
промышленное оборудование
сырье и материалы
социальные сети
средства связи
образование и обучение
WmLink
LiveClix
Реклама от LiveCLiX
Понедельник, 06.05.2024, 18:36
Приветствую Вас Гость | RSS
Главная | Регистрация | Вход
Композиция функций

Композиция функций



Вот еще пример простого приложения — опросника.


Необходимо ответить на каждый блок. Каждый блок содержит несколько вопросов. После ответа на один блок, мы переходим к следующему.

Каждый блок можно представить как панель, которая может быть в режиме вопроса, режиме результата или неактивной.



В каждой панели могут быть разные поля. Строковые, числовые, даты.
Поля могут быть в двух режимах — редактирования или результата.

Посмотрим, как можно подойти к решению этой задачи, используя функциональный подход.

Помните нашу любимую функцию prop?

tweeps.map(prop("name"));


У нее есть брат-близнец func.

tweeps.map(func("to.String"));

Она возвращает функцию, которую вы можете применять к объектам.

Теперь посчитаем результат каждого блока в опроснике

buildSummary: function(){
 return div(this.components.map(func("buildSummary")));
}


Принцип должен быть очевиден. Мы возвращаем div, в котором будут элементы, созданные функциейbuildSummary для каждого блока опросника.

В этом примере каждый компонент сам знает как представить свой результат. Но иногда панель должна отобразить результат специфическим образом.

Поэтому мы можем написать 2 функции: buildSummary и getSummary.

Первая — строит полное представление, включая html теги.
Вторая — возвращает объект, который содержит необходимые результаты.

И как только нам понадобилась хитрая обработка результатов, вся красота начала рушиться.

buildSummary: function(){
 var div = document.createElement("div");


 for(var i =0; l=this.components.length; i<l; ++i)
 {
 p = document.CreateElement("p");
 p.innerHTML = this.components[i].getSummary().text;
 div.appendChild(p);
 }
 return div;
}


Однако, мы уже достаточно функционально ориентированы, чтобы улучить этот кусок кода. Первое очевидное улучшение — применить foreach.

buildSummary : function(){
 var div = document.createElement("div");
 
 this.components.forEach(function(component){
 var p = document.createElement("p");
 p.innerHTML = component.getSummary().text;
 div.appendChild(p);
 });

 return div;
}


Мы избавились от переменных цикла, но возможно ли использовать map?

buildSummary : function(){
 return div(this.components.map(function(component){
 var p = document.createElement("p");
 p.innerHTML = component.getSummary().text;
 return p;
 }));
}


Коротко, но далеко до идеала. Основная проблема в этом выражении:
component.getSummary().text;


Проблема в том, тут происходит не одна, а целых три вещи:
  1. Получение результата через getSummary()
  2. Получение свойства text
  3. Оборачивание результата в тег p


А как насчет нескольких функций map?

buildSummary: function() {
 return div(this.components.
 map(function(component){
 return component.getSummary();
 }).map(function(summary){
 return summary.text;
 }).map(function(text){
 var p = document.createElement("p");
 p.innerHTML = text;
 return p;
 }));
}


Функциональный стиль налицо, но выглядит страшно. И читать очень неудобно.

Но давайте глянем на код еще разок. Что у нас здесь?

return component.getSummary();


Здесь мы вызываем метод объекта. Но ведь мы создали специальную функцию для этого, func.

buildSummary: function() {
 return div(this.components.
 map(func("getSummary")).
 map(function(summary){
 return summary.text;
 }).map(function(text){
 var p = document.createElement("p");
 p.innerHTML = text;
 return p;
 }));
}


А здесь?

function(summary){
 return summary.text;
}


Мы получаем доступ к свойству объекта. И для этого тоже есть удобная функция.

buildSummary: function() {
 return div(this.components.
 map(func("getSummary")).
 map(prop("text")).
 map(function(text){
 var p = document.createElement("p");
 p.innerHTML = text;
 return p;
 }));
}

Остался последний участок.
function(text){
 var p = document.createElement("p");
 p.innerHTML = text;
 return p;
 }


Мы здесь создаем DOM элемент и устанавливаем его внутреннее свойство. У нас есть что-то похожее в нашем DSL, не правда ли?

buildSummary: function() {
 return div(this.components.
 map(func("getSummary")).
 map(prop("text")).
 map(p));
}

Теперь почти красиво. Но есть один нюанс. Мы делаем 3 прохода по списку. В каких-то случаях это может быть нормально, но в целом несколько неоптимально. Что же можно сделать?

Пора использовать композицию функций. Мы хотим заставить одну функцию делать то, что делают три.

var summarize = compose(
 [p, prop("text"), func("getSummary")]);
Copyright MyCorp © 2024
Сделать бесплатный сайт с uCoz