程序解决的问题为:给一个json,以表格的形式输出它。
表格的格式是左对齐或者右对齐,表格头部有下划线标识,每个表格块的大小取决于该行最大高,和该列最大宽。
以对象的思维方式去解决。
需要一个表格块对象,该对象保存该块的宽和高,字符内容(因为该块有可能是多行字符,随意用字符数组保存),以及讲该快画成指定格式的draw函数。
然后是一个表头对象,该对象使用表格对象的方法。
dataTable()函数将数据处理成二维数组。
drawTable将该二维数组格式化为字符串。
用到很多map,reduce。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
var MOUNTAINS = [
{name: ["aaaaa \nkkkk\n\n\nnn\n dsadasd\ndjsioajdoiwjioajwdoioj"], height: "aaa", country: "aaaaa"},
{name: "aaaaa", height: 8848, country: "Nepal"},
{name: "Mount Fuji", height: 3776, country: "Japan"},
{name: "Mont Blanc", height: 4808, country: "Italy/France\ndfjsioajdiojaijdioajoidjoijasoijdwoijiod"},
{name: "Vaalserberg", height: 323, country: "Netherlands"},
{name: "Denali", height: 6168, country: "United States"},
{name: "Popocatepetl", height: 5465, country: "Mexico"}
];
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)//这里必须为0 ,如果是默认,reduce会在第二个值开始进行合并操作, 这里的默认初始值为row为数组
})
}
function repeat(string, times){
var result="";
for(var i=0;i<times;i++){
result+=string;
}
return result;
}
function TextCell(text){
this.text=text.split("\n");
}
TextCell.prototype.minWidth = function() {
return this.text.reduce(function(width, line) {
return Math.max(width, line.length);
}, 0);
};
TextCell.prototype.minHeight = function() {
return this.text.length;
};
TextCell.prototype.draw=function(width, height){
var result=[];
for(var i=0;i<height;i++){
var line=this.text[i]||"";
console.log(line);
result.push(line+repeat(" ",width-line.length));
}
return result;
}
function UnderlineCell(inner){
this.inner = inner;
}
UnderlineCell.prototype.minWidth = function() {
return this.inner.minWidth();
};
UnderlineCell.prototype.minHeight = function() {
return this.inner.minHeight() + 1;
};
UnderlineCell.prototype.draw = function(width, height) {
return this.inner.draw(width, height - 1)
.concat([repeat("-", width)]);
};
function dataTable(data){
var keys=Object.keys(data[0]);
var header=keys.map(function(name){
return new UnderlineCell(new TextCell(name));
});
var body=data.map(function(row){
return keys.map(function(name){
var value=row[name];
if(typeof name == "number")
return new RTextCell(String(value));
else
return new TextCell(String(value));
})
});
return [header].concat(body);
}
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");
}
//继承
function RTextCell(text){
TextCell.call(this,text);//这里call调用TextCell函数,这里为分离组合继承
}
RTextCell.prototype=Object.create(TextCell.prototype);
RTextCell.prototype.draw=function(width,height){
var result=[];
for(var i=0;i<height;i++){
var line=this.text[i]||"";
result.push(repeat(" ",width-line.length)+line);
}
return result;
}
console.log(Object.getPrototypeOf(TextCell) ==Object.getPrototypeOf(UnderlineCell));
console.log(drawTable(dataTable(MOUNTAINS)));
</script>
</body>
</html>