Не бойтесь функционального программирования

27 Августа 2014 2707 , , ,

Функциональное программирование — это усатый хипстер парадигм программирования. Обращаясь к хронике академии информатики, у функционального программирования было недавнее возрождение, которое обусловлено его утилитой в распределенных системах (и вероятно также, потому что “чистые” функциональные языки как Haskell трудно понять, что определенным образом отличает их).

fp-preview

Более строгие языки функционального программирования обычно используются, когда производительность и целостность системы критически важны — т.е. Ваша программа должна сделать точно, что Вы ожидаете каждый раз, и должны управлять в среде, где ее задачи могут быть совместно использованы через сотни или тысячи подключенных к сети компьютеров. Clojure, например, Akamai, крупная сеть доставки контента, используемая компаниями, такими как Facebook, в то время как Twitter отлично принял Scala для своих самых интенсивных производительностью компонентов, и Haskell используется AT&T для его систем сетевой безопасности.

У этих языков есть крутая кривая обучения для большинства веб-разработчиков фронтэнда; однако, еще много доступных языков включают функции функционального программирования, прежде всего Python, оба в его оперативной библиотеке, с функциями как map и reduce (о котором мы будем немного говорить), и с библиотеками, такими как Fn.py, вместе с JavaScript, снова используя методы набора, но также и с библиотеками, такими как Underscore.js и Bacon.js.

Функциональное программирование может быть пугающим, но помните, что это не только для PhDs, ученых данных и астронавтов архитектуры. Для большинства из нас реальная выгода принятия функционального стиля — то, что наши программы могут быть разломаны на меньшие, более простые части, которые и более надежны и проще понять. Если Вы будете разработчиком фронтэнда, работающим с данными, особенно если Вы отформатируете те данные для визуализации, используя D3, Raphael и т.п., то функциональное программирование будет существенным оружием в Вашем арсенале.

Нахождение непротиворечивого определения функционального программирования трудно, и большая часть литературы полагается на  такие утверждения, как “функции как первоклассные объекты”, и “устранение побочных эффектов”. На всякий случай,  это не должно особо ломать мозг,  на более теоретическом уровне функциональное программирование часто объясняется с точки зрения λ-исчисления (некоторые фактически утверждают, что функциональное программирование — в основном математика) —, но Вы можете расслабиться. С более прагматической точки зрения новичок должен понять только два понятия, чтобы использовать ее для повседневных приложений (исчисление не требуется!).

Во-первых, данные в функциональных программах должны быть неизменными, это звучит серьезно, но просто означает, что они никогда не должны изменяться. Сначала, это могло бы казаться странным (в конце концов, кто нуждается в программе, которая никогда ничего не изменяет?), но на практике, Вы просто создали бы новые структуры данных вместо того, чтобы изменять существующие. Например, если бы Вы должны были управлять некоторыми данными в массиве, тогда Вы сделали бы новый массив с обновленными значениями, а не изменяли бы исходный массив. Просто!

Во-вторых, функциональные программы не должны сохранять свое состояние, что в основном означает, что они должны выполнить каждую задачу, как будто впервые, без знания того, что может или могло не произойти ранее в выполнении программы (Вы могли бы сказать, что программа не сохраняющая состояние не осведомлена о прошлом). В сочетании с неизменностью, это помогает нам думать о каждой функции, как будто это работает в вакууме, блаженно неосведомленном о чем-либо еще в приложении помимо других функций. В более конкретных терминах это означает, что Ваши функции будут воздействовать только на данные, передаваясь в качестве аргументов, и никогда не будут полагаться на внешние значения, чтобы выполнить свои вычисления.

Неизменность и не сохраняющееся состояние является ядром к функциональному программированию и необходимо для понимания, но не волнуйтесь если они еще не совсем имеет смысл. Вы будете знакомы с этими принципами к концу статьи, и я обещаю, что красота, точность и мощность функционального программирования превратят Ваши приложения в яркие, солнечные, громко жующие данные радуги. На данный момент начните с простых функций, которые возвращают данные (или другие функции), и затем комбинируют те основные стандартные блоки, чтобы выполнить более сложные задачи.

Например, скажем, у нас есть ответ API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var data =[
{
name:"Jamestown",
population:2047,
temperatures:[-34,67,101,87]
},
{
name:»Awesome Town»,
population:3568,
temperatures:[-3,4,9,12]
}
{
name:»Funky Town»,
population:1000000,
temperatures:[75,75,75,75,75]
}
];

Если мы хотим использовать диаграмму или библиотеку построения графика, чтобы сравнить среднюю температуру с численностью населения, мы должны были бы записать некоторый JavaScript, который вносит несколько изменений в данные, прежде чем это будет отформатировано правильно для нашей визуализации. Наша библиотека построения графика хочет массив x и координат y, вот так:

1
2
3
4
5
[
[x,y],
[x,y]
…etc
]

Здесь, x — средняя температура, и y — численность населения.

Без функционального программирования (или не используя то, что зовется “обязательный” стиль), наша программа могла бы быть похожей на это:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var coords =[],

totalTemperature =0,

averageTemperature =0;

for(var i=0; i < data.length; i++){

totalTemperature =0;

for(var j=0; j < data[i].temperatures.length; j++){

totalTemperature += data[i].temperatures[j];

}

averageTemperature = totalTemperature / data[i].temperatures.length;

coords.push([averageTemperature, data[i].population]);

}

Даже в придуманном примере, это уже становится трудным следовать. Давайте посмотрим, можем ли мы добиться большего успеха.

При программировании в функциональном стиле Вы всегда ищете простые, повторяемые действия, которые могут быть абстрагированы в функцию. Мы можем тогда создать более сложные функции, вызывая эти функции в последовательности (также известно как “создание” функций) — больше об этом через секунду. Тем временем давайте смотреть на шаги, которые мы сделали бы в процессе преобразования начального ответа API в структуру, требуемую нашей библиотекой визуализации. На базовом уровне мы выполним следующие действия с нашими данными:

  •  добавьте каждое число в список,
  •  вычислите среднее число,
  • получите единственное свойство из списка объектов.

Мы запишем функцию для каждого из этих трех основных действий, затем составим нашу программу из тех функций. Функциональное программирование может немного сбить с толку сначала, и Вы, вероятно, испытаете желание проскользнуть в старые обязательные привычки. Во избежание этого вот некоторые простые правила, которые гарантируют, что Вы следуете лучшим практикам:

  1. Все Ваши функции должны принять по крайней мере один параметр.
  2. Все Ваши функции должны возвратить данные или другую функцию.
  3. Никаких циклов!

Хорошо, давайте добавим каждое число в список. При запоминании правил давайте удостоверимся, что наша функция принимает параметр (массив чисел, чтобы добавить) и возвращает некоторые данные.

1
2
3
4
5
6
7
functiontotalForArray(arr){

//добавьте все

return total;

}

Пока неплохо. Но как мы собираемся получить доступ к каждому элементу в списке, если мы не циклично выполняемся по нему? Скажите привет Вашему новому другу, рекурсии! Это немного сложнее, но в основном, когда Вы используете рекурсию, Вы создаете функцию, которая вызывает себя, если особое условие не соблюдали —  значение возвращено. Рассмотрение примера является, вероятно, самым простым:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//Заметьте, что мы принимаем два значения, список и текущее общее количество

functiontotalForArray(currentTotal, arr){

currentTotal += arr[0];

// Заметка опытным программистам JavaScript, я не использую Array.shift  нарочно

// потому что мы рассматриваем массивы, как будто они неизменные.

var remainingList = arr.slice(1);

// Эта функция вызывает себя с остальной частью списка

// и текущим значением переменной currentTotal

if(remainingList.length >0){

returntotalForArray(currentTotal, remainingList);

}

// Если, конечно, список не пуст, в этом случае мы можем просто вернуть

// значение currentTotal.

else{

return currentTotal;

}

}

Слово предостережения: Рекурсия сделает Ваши программы более читаемыми, и это важно для программирования в функциональном стиле. Однако на некоторых языках (включая JavaScript), Вы столкнетесь с проблемами, когда Ваша программа сделает большое количество рекурсивных вызовов в единственной работе (во время записи, “большой” приблизительно 10,000 вызовов в Chrome, 50,000 в Firefox и 11,000 в Node.js). Детали выходят за рамки этой статьи, но суть в том, что, по крайней мере пока ECMAScript 6 не выпущен, JavaScript не поддерживает что-то вызванное “хвостовая рекурсия”, которая является более эффективной формой рекурсии. Это — усовершенствованная тема и не будет подходить очень часто, но это стоит знать.

Теперь, когда путь свободен, вспоминайте, что мы должны были вычислить полную температуру от массива температур, чтобы после вычислить среднее число. Теперь, вместо цикличного выполнения по каждому элементу в массиве температур, мы можем просто записать это:

1
var totalTemp=totalForArray(0,temperatures);

Если Вы — пурист, Вы могли бы сказать, что наша totalForArray функция могла быть сломана еще больше. Например, задача добавления двух чисел вместе, вероятно, подойдет в других частях Вашего приложения и впоследствии должна действительно быть своей собственной функцией.

1
2
3
functionaddNumbers(a,b){
return a + b;
}

Теперь totalForArray функция выглядит вот так:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
functiontotalForArray(currentTotal, arr){

currentTotal =addNumbers(currentTotal, arr[0]);

var remainingArr = arr.slice(1);

if(remainingArr.length >0){

returntotalForArray(currentTotal, remainingArr);

}

else{

return currentTotal;

}
}

Отлично! Возврат единственного значения от массива довольно распространен в функциональном программировании, настолько, что даже есть специальное понятие, “сокращение”, которое Вы будете более часто слышать как глагол, чем  “уменьшите массив до единственного значения”. У JavaScript есть специальный метод только для выполнения этой общей задачи. Сеть Разработчика Mozilla обеспечивает полное объяснение, но в наших целях это настолько просто:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Метод reduce берет функцию в качестве своего первого параметра,

// и эта функция принимает и текущий элемент в списке

// и текущий общий результат безотносительно вычисления, которое Вы выполняете.

var totalTemp = temperatures.reduce(function(previousValue, currentValue){

// После того, как это вычисление возвращено, следующий currentValue

// будет previousValue + currentValue, и следующий previous

// Value будет следующим элементом в массиве.

returnpreviousValue+currentValue;

});

Но! так как мы уже определили функцию addNumber, мы можем просто использовать ее вместо этого.

1
var totalTemp = temperatures.reduce(addNumbers);

Фактически, так как массив настолько классный, давайте помещать это в его собственную функцию так, чтобы мы могли использовать его снова, не имея необходимость помнить весь тот запутывающий материал о сокращении и рекурсии.

1
2
3
4
5
6
7
functiontotalForArray(arr){

return arr.reduce(addNumbers);

}

var totalTemp =totalForArray(temperatures);

Теперь это некоторый читаемый код! Просто, чтобы Вы знали, методы те, которые уменьшают, распространены в языках наиболее функционального программирования. Эти методы помощника, которые выполняют действия с массивами вместо цикличного выполнения, часто называются “функциями высшего порядка”.

Движущееся дальше, вторая задача, которую мы перечисляли, вычисляла среднее число. Это довольно просто:

1
2
3
4
5
functionaverage(total, count){

return total / count;

}

Как мы может прийти к получению среднего числа для всего массива?

1
2
3
4
5
6
7
functionaverageForArray(arr){

returnaverage(totalForArray(arr), arr.length);

}

varaverageTemp=averageForArray(temperatures);

Хотелось бы надеяться, что Вы начинаете видеть, как объединить функции, чтобы выполнить более сложные задачи. Это возможно, потому что мы выполнили набор правил до конца в начале этой статьи — а именно, что наши функции должны всегда принимать данные возврата и параметры. Довольно удивительно.

Наконец, мы хотели получить единственное свойство от массива объектов. Вместо того, чтобы показать Вам больше примеров рекурсии, я расскажу о другом встроенном методе JavaScript: map. Этот метод используется, когда у Вас есть массив с одной структурой и потребностью отобразить его на другую структуру, как так:

1
2
3
4
5
6
7
8
9
// Метод map берет единственный параметр, текущий элемент в списке.

// Проверьте ссылку выше для большего количества полных примеров.

var allTemperatures = data.map(function(item){

returnitem.temperatures;

});

Это довольно классно, но получение по запросу единственного свойства от набора объектов является тем, что Вы будете делать все время, поэтому давайте сделаем функцию только для этого.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Передайте в имени свойства, которое Вы хотели бы получить

functiongetItem(propertyName){

// Возвратите функцию, которая получает тот элемент,

// но не выполняйте функцию. Мы оставим это до метода,

// который принимает меры на элементах в нашем массиве.

returnfunction(item){

return item[propertyName];

}
}

Вы только посмотрите!: Мы сделали функцию, которая возвращает функцию! Теперь мы можем передать его к методу map вот так:

1
var temperatures = data.map(getItem('temperature'));

В случае, если Вам нравятся детали, причина по которой мы можем сделать это вызвана тем, что в JavaScript, функции — “первоклассные объекты”, который в основном означает, что Вы можете раздать функции точно так же, как любое другое значение. Это функция многих языков программирования, это требование любого языка, который может использоваться в функциональном стиле. Случайно, это — также причина, Вы можете сделать материал как $ (‘#my-element’) .on (‘щелчок’, функция (e) …). Вторым параметром в  методе является функция, и когда Вы передаете функции как параметры, Вы используете их точно так же, как Вы использовали бы значения в императивных языках. Довольно аккуратно.

Наконец, давайте обертывать вызов к map, чтобы отобразить в его собственной функции, чтобы сделать вещи немного более читаемыми.

1
2
3
4
5
6
7
functionpluck(arr, propertyName){

return arr.map(getItem(propertyName));

}

var allTemperatures =pluck(data,'temperatures');

Хорошо, теперь у нас есть инструментарий общих функций, которые мы можем использовать где угодно в нашем приложении, даже в других проектах. Мы можем соответствовать элементам в массиве, получить среднее значение массива и сделать новые массивы, выдергивая свойства из списков объектов. Наконец, что не менее важно, давайте возвратимся к нашей исходной проблеме:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var data =[

{

name:"Jamestown",

population:2047,

temperatures:[-34,67,101,87]

},



];

 

Мы должны преобразовать массив объектов как тот выше в массив x, y пары:

1
2
3
4
5
6
7
[

[75,1000000],



];

Здесь, x — средняя температура, и y — общая численность населения. Во-первых, давайте выделим данные, в которых мы нуждаемся.

1
2
3
var populations =pluck(data,'population');

var allTemperatures =pluck(data,'temperatures');

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

1
var averageTemps = allTemperatures.map(averageForArray);

Пока неплохо. Но теперь у нас есть два массива:

1
2
3
4
5
6
7
// население

[2047,3568,1000000]

// averageTemps

[55.25,5.5,75]

 

Очевидно, мы хотим только один массив, поэтому давайте запишем функцию, чтобы объединить их. Наша функция должна удостовериться, что элемент по индексу 0 в первом массиве соединен с элементом по индексу 0 во втором массиве, и т.д. для индексов 1 к n (где n — общее количество элементов в массиве).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
functioncombineArrays(arr1, arr2, finalArr){

// Именно так мы не должны забывать передавать пустой массив как третий параметр

// при вызывании этой функции, мы установим значение по умолчанию.

finalArr = finalArr ||[];

// Продвиньте элемент current в каждом массиве в тот, что мы в конечном счете возвратим

finalArr.push([arr1[0], arr2[0]]);

var remainingArr1 = arr1.slice(1),

remainingArr2 = arr2.slice(1);

// Если оба массива пусты, то мы сделаем

if(remainingArr1.length ===0&& remainingArr2.length ===0){

return finalArr;

}

else{

// Рекурсия!

returncombineArrays(remainingArr1, remainingArr2, finalArr);

}

};

var processed =combineArrays(averageTemps, populations);

Или, потому что однострочечники забавны:

1
2
3
4
5
6
7
8
9
10
11
var processed =combineArrays(pluck(data,'temperatures').map(averageForArray),pluck(data,'population'));

// [

//  [ 55.25, 2047 ],

//  [ 5.5, 3568 ],

//  [ 75, 1000000 ]

// ]

Давайте вернемся к реальности

Наконец, что не менее важно, давайте смотреть на еще один реальный пример, на сей раз добавляя к нашему функциональному инструментарию с Underscore.js, библиотеку JavaScript, которая предоставляет ряд великих функциональных помощников программирования. Мы вытянем данные с платформы для конфликта и информации о бедствии, я работаю под названным CrisisNET, и мы будем пользоваться фантастической библиотекой D3, чтобы визуализировать эти данные.

Цель состоит в том, чтобы дать людям, переходящих на домашнюю страницу CrisisNET быстрый снимок типов информации в системе. Чтобы демонстрировать это, мы могли считать число документов от API, которые присвоены определенной категории, как “физическое насилие” или “вооруженный конфликт”. Таким образом, пользователь видит, сколько информации доступно по темам, которые они считают самыми интересными.

Круговая диаграмма могла бы быть подходящим вариантом, потому что они часто используются, чтобы представлять относительные размеры многочисленных групп людей. К счастью, у D3 есть встроенная визуализация, названная pack именно для этой цели. Так, давайте создадим график с pack, который показывает число раз, когда имя данной категории появляется в ответе от API CrisisNET.

Прежде чем мы продолжим, обратите внимание на то, что D3 — сложная библиотека, которая гарантирует ее собственное учебное руководство (или много учебных руководств, в этом направлении). Поскольку эта статья фокусируется на функциональном программировании, мы не потратим много времени на то, как D3 работает. Но не волнуйтесь — если Вы еще не знакомы с библиотекой, вам необходимо скопировать и вставить фрагменты кода, определенные для D3 и вставьте  в детали другое время. Учебные руководства Скотта Мюррея D3 — большой ресурс, если Вы заинтересованы в углубленных знаниях.

Далее, давайте сначала удостоверяться, что у нас есть элемент DOM, так, чтобы у D3 было некоторое место, чтобы поместить диаграмму, которая воспроизводится с нашими данными.

1
<div id="bubble-graph"></div>

Теперь, давайте составим нашу таблицу и добавим ее к DOM.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// ширина диаграммы

var diameter =960,

format = d3.format(",d"),

// создает порядковую шкалу с 20 цветами. См. документы D3 для шестнадцатеричных значений

color = d3.scale.category20c(),

// постройте диаграмму объекта, к которой мы будем добавлять данные

var bubble = d3.layout.pack()

.sort(null)

.size([diameter, diameter])

.padding(1.5);

// Добавьте SVG к DOM, который наш объект пакета будет использовать, для составления

//  визуализации.

var svg = d3.select("#bubble-graph").append("svg")

.attr("width", diameter)

.attr("height", diameter)

.attr("class","bubble");

Объект pack берет массив объектов в этом формате:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{

children:[

{

className:,

package:"cluster",

value:

}

]

}

API данных CrisisNET возвращает информацию в этом формате:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{

data:[

{

summary:"Example summary",

content:"Example content",



tags:[

{

name:"physical-violence",

confidence:1

}

]

}

]

}

Мы видим, что у каждого документа есть свойство tags, и что свойство содержит массив элементов. У каждого элемента тега есть свойство name, которое является тем, что мы после(which is what we’re after). Мы должны найти каждое уникальное имя тега в ответе API CrisisNET и считать число раз, когда имя тега появляется. Давайте запускаться, выделяя информацию, мы нуждаемся в использовании функции pluck, который мы создали ранее.

1
var tagArrays =pluck(data,'tags');

Это дает нам массив массивов:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[

[

{

name:"physical-violence",

confidence:1

}

],

[

{

name:"conflict",

confidence:1

}

]

]

Однако то, что мы действительно хотим, является одним массивом с каждым тегом в нем. Так, давайте использовать удобную функцию Underscore.js, названную сглаживание(flatten). Она примет значения от любых вложенных массивов и даст нам массив, который будет уровнем глубже.

1
vartags= _.flatten(tagArrays);

Теперь, нашему массиву немного проще иметь дело с:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[

{

name:"physical-violence",

confidence:1

},

{

name:"conflict",

confidence:1

}

]

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

1
2
3
4
5
6
7
8
9
var tagNames =pluck(tags,'name');

[

"physical-violence",

"conflict"

]

Так лучше. Теперь относительно простых задач подсчета чисел каждый раз, когда имя тега появляется в нашем списке и затем преобразовании, которые перечисляют в структуру, требуемую расположением  D3 pack, которое мы создали ранее. Как Вы, вероятно, заметили, массивы — довольно популярная структура данных в функциональном программировании — большинство инструментов разработано с массивами в памяти. Как первый шаг, тогда, мы создадим массив:

1
2
3
4
5
6
7
[

["physical-violence",10],

["conflict",27]

]

Здесь, у каждого элемента в массиве есть имя тега по индексу 0 и что общее количество тега по индексу 1. Мы хотим только один массив для каждого уникального имени тега, поэтому давайте запускаться, создавая массив, в котором каждое имя тега появляется только один раз. К счастью, метод Underscore.js существует именно для этой цели.

1
vartagNamesUnique= _.uniq(tagNames);

Давайте также избавимся от любого false-y (false, null, «», etc.) значения, используя другую удобную Underscore.js функцию:

1
tagNamesUnique= _.compact(tagNamesUnique);

Отсюда, мы можем записать функцию, которая генерирует наши массивы, используя другой встроенный метод набора JavaScript, названный фильтром (filter), который фильтрует массив на основе условия.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
functionmakeArrayCount(keys, arr){

// для каждого из уникальных tagNames

return keys.map(function(key){

return[

key,

// Найдите все элементы в полном списке имен тега, которым соответствуют этот ключ

// и считают размер возвращенного массива.

arr.filter(function(item){return item === key;}).length

]

});

}

Мы можем теперь легко создать структуру данных, которую pack требует, отображая наш список массивов.

1
2
3
4
5
6
7
8
9
10
11
12
13
var packData =makeArrayCount(tagNamesUnique, tagNames).map(function(tagArray){

return{

className: tagArray[0],

package:"cluster",

value:tagArray[1]

}

});

Наконец, мы можем передать наши данные к D3 и генерировать узлы DOM в нашем SVG, один круг для каждого уникального имени тега, измеренного относительно общего количества времен, когда имя тега появилось в ответе API CrisisNET.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
functionsetGraphData(data){

var node = svg.selectAll(".node")

// Вот то, где мы передаем наши данные к объекту пакета.

.data(bubble.nodes(data)

.filter(function(d){return!d.children;}))

.enter().append("g")

.attr("class","node")

.attr("transform",function(d){return"translate("+ d.x +","+ d.y +")";});

// Добавьте круг для каждого имени тега.

node.append("circle")

.attr("r",function(d){return d.r;})

.style("fill",function(d){returncolor(d.className);});

//Добавьте метку к каждому кругу, используя имя тега в качестве текста метки

node.append("text")

.attr("dy",".3em")

.style("text-anchor","middle")

.style("font-size","10px")

.text(function(d){return d.className });

}

Собираем все вместе, вот функции setGraphData и makeArray в контексте, включая вызов к API CrisisNET, используя jQuery (Вы должны будете получить ключ API). Я также отправил полностью рабочий пример на GitHub.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
functionprocessData(dataResponse){

var tagNames =pluck(_.flatten(pluck(dataResponse.data,'tags')),'name');

var tagNamesUnique = _.uniq(tagNames);

var packData =makeArrayCount(tagNamesUnique, tagNames).map(function(tagArray){

return{

className: tagArray[0],

package:"cluster",

value: tagArray[1]

}

});

return packData;

}

functionupdateGraph(dataResponse){

setGraphData(processData(dataResponse));

}

var apikey = // Get an API key here: http://api.crisis.net

var dataRequest = $.get('http://api.crisis.net/item?limit=100&apikey='+ apikey);

dataRequest.done(updateGraph);

Это было довольно глубоким погружением, мои поздравления, продолжайте усердно работать! Как я упоминал, эти понятия могут быть сложными вначале, но сопротивляйтесь искушению работать с циклами всю свою жизнь.

В течение нескольких недель после использования методов функционального программирования Вы быстро создадите ряд простых, допускающих повторное использование функций, которые существенно улучшат удобочитаемость Ваших приложений. Плюс, Вы будете в состоянии управлять структурами данных значительно более быстро, выводя из строя то, что раньше было 30 минутами срыва отладки в паре строк кода. Как только Ваши данные были отформатированы правильно, Вы сможете потратить больше времени на забавные части: чтобы заставить визуально выглядеть удивительно!

По материалам: smashingmagazine.com

Подписывайтесь на обновления

Читайте RSS ленту

Комментарии

  • Алёна ответить
    12.02.2015 в 10:50

    За статью огромная благодарность, все по делу.

  • Trinity ответить
    16.02.2015 в 12:58

    а еще посты на эту тему будут в будущем?

    • strokoff ответить
      18.02.2015 в 10:06

      Да, вы можете предложить тему для следующих постов.

Добавить комментарий