Выразительный JavaScript (Хавербеке) - страница 63

• minHeight() возвращает число, показывающее минимальную высоту, которую требует ячейка (выраженную в строчках)

• minWidth() возвращает число, показывающее минимальную ширину, которую требует ячейка (выраженную в символах)

• draw(width, height) возвращает массив длины >height, содержащий наборы строк, каждая из которых шириной в >width символов. Это содержимое ячейки.

Я буду использовать функции высшего порядка, поскольку они здесь очень уместны.

Первая часть программы вычисляет массивы минимальных ширин колонок и высот строк для матрицы ячеек. Переменная >rows будет содержать массив массивов, где каждый внутренний массив – это строка ячеек.

>function rowHeights(rows) {

>  return rows.map(function(row) {

>    return row.reduce(function(max, cell) {

>      return Math.max(max, cell.minHeight());

>    }, 0);

>  });

>}


>function colWidths(rows) {

>  return rows[0].map(function(_, i) {

>    return rows.reduce(function(max, row) {

>      return Math.max(max, row[i].minWidth());

>    }, 0);

>  });

>}

Используя переменную, у которой имя начинается с (или полностью состоит из) подчёркивания (>_), мы показываем тому, кто будет читать код, что этот аргумент не будет использоваться.

Функция >rowHeights не должна вызвать затруднений. Она использует >reduce для подсчёта максимальной высоты массива ячеек, и заворачивает это в >map, чтобы пройти все строки в массиве >rows.

Ситуация с >colWidths посложнее, потому что внешний массив – это массив строк, а не столбцов. Я забыл упомянуть, что >map (как и >forEach, >filter и похожие методы массивов) передаёт в заданную функцию второй аргумент – индекс текущего элемента. Проходя при помощи >map элементы первой строки и используя только второй аргумент функции, >colWidths строит массив с одним элементом для каждого индекса столбца. Вызов >reduce проходит по внешнему массиву >rows для каждого индекса, и выбирает ширину широчайшей ячейки в этом индексе.

Код для вывода таблицы:

>function drawTable(rows) {

>  var heights = rowHeights(rows);

>  var widths = colWidths(rows);


>  function drawLine(blocks, lineNo) {

>    return blocks.map(function(block) {

>      return block[lineNo];

>    }).join(" ");

>  }


>  function drawRow(row, rowNum) {

>    var blocks = row.map(function(cell, colNum) {

>      return cell.draw(widths[colNum], heights[rowNum]);

>    });

>    return blocks[0].map(function(_, lineNo) {

>      return drawLine(blocks, lineNo);

>    }).join("\n");

>  }


>  return rows.map(drawRow).join("\n");

>}

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