目录
- 一、介绍
- 二、准备
- 三、目标
- 四、代码
- 五、完成
一、介绍
JSON 已经是大家必须掌握的知识点,JSON 数据格式为前后端通信带来了很大的便利。在开发中,前端开发工程师可以借助于 JSON 生成器快速构建一个 JSON 用来模拟数据。
本题请你开发一个简易的 JSON 生成器工具,使它能根据模板生成对应格式的 JSON 。
二、准备
开始答题前,需要先打开本题的项目代码文件夹,目录结构如下:
├── css
├── index.html
└── js
├── highlight.min.js
└── index.js
其中:
- css 是样式文件夹。
- index.html 是主页面。
- js/highlight.min.js 是 json 格式化文件。
- js/index.js 是需要补充代码的 js 文件。
在浏览器中预览 index.html 页面效果如下:
三、目标
请在 index.js 文件中补全 generateData 函数代码,并最终返回一个 js 对象(说明 : generateData 生成的数据会由插件自动转化成 JSON)。
在左侧的输入框中输入指定格式的数据模板,点击生成 JSON 按钮,右侧会自动生成对应格式的 JSON 数据。
- 数据模板中对象的 key 对应的 value 如果是 {{}} 并且符合下述规则,则根据下述规则解析,否则一律返回原始 value 值。具体规则如下:
- {{bool()}} 表示随机生成布尔值。
- {{integer(n, m)}} 表示生成 n-m 之间(包含 n、m )的随机整数(注意:n<m)。
附目标 1 测试用例:
{
isPass: '{{bool()}}',
age: '{{integer(3, 5)}}',
goodsNumber:2,
isShow:false,
tag:'phone',
fn:'{{integer}}'
}
- 数据模板中 {{repeat()}}(此项只会出现在数组首位)表示重复生成数组中的数据,如:“repeat(5, 7)” 则表示随机生成 5-7 条数组数据,repeat 中值只包含一个数字,如"repeat(5)" 表示生成 5 条数组数据。
附目标 2 测试用例(3 组):
// (1)随机生成 `2-5` 条数组数据
[
"{{repeat(2, 5)}}",
{
isActive: "{{bool()}}",
age: "{{integer(20, 40)}}",
num: 2,
boolean: true,
str: "str",
isTel: "{{bool}}",
fn: "{{fn()}}",
},
]
// (2)固定生成 `7` 条数组数据
[
("{{repeat(7)}}",
{
isTrue: "{{bool()}}",
score: "{{integer(3, 7)}}",
tag: "android",
isSamll: true,
fn: "{{fn()}}",
})
]
// (3)无 repeat 的情况
[
{ maxNum: 10 }
];
注意:本题不考虑用户输入和传参不合法的情况,只处理合法的数据格式即可,实际测试中 key 和 value 为非固定值。提供的测试用例仅为方便测试代码使用,实际使用中需要对所有符合要求的数组/对象结构的模板生效。
四、代码
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JSON 生成器</title>
<link rel="stylesheet" href="./css/default.min.css" />
<script src="./js/highlight.min.js"></script>
<script>
hljs.highlightAll();
</script>
</head>
<body>
<div class="btnbox" id="btnbox">
<button class="btn" onclick="generate()">生成json</button>
</div>
<div class="con">
<div class="left">
<textarea id="myTextarea" name="myTextarea"> </textarea>
</div>
<div>
<pre>
<code id="code " class="language-js "></code>
</pre>
</div>
</div>
<script>
let myTextarea = document.getElementById("myTextarea");
myTextarea.innerHTML = `[
'{{repeat(2, 3)}}',
{
isActive: '{{bool()}}',
age: '{{integer(20, 40)}}',
num:2,
boolean:true,
str:'str',
isTel:'{{bool}}',
fn:'{{fn()}}'
}
]`;
let code = document.getElementById("code ");
let lastData;
// 点击生成按钮生成对应的 JSON
function generate() {
let str = myTextarea.value.replace(/\s*/g, "");
var jsonData = new Function("return" + str)();
lastData = generateData(jsonData);
let jsonCode = JSON.stringify(lastData, null, 2); // 设置 tab 为两个空格
code.innerHTML = jsonCode;
hljs.highlightAll();
}
</script>
<script src="./js/index.js "></script>
</body>
</html>
js/index.js
/*
* @param {*} 左侧输入框输入的值转化成的 js 数据
* @return {*} 根据传入的数据生成对应的 js 格式数据
*/
let generateData = (data) => {
// TODO:待补充代码
};
module.exports = { generateData };
css/default.min.css
/*!
Theme: Default
Description: Original highlight.js style
Author: (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
Maintainer: @highlightjs/core-team
Website: https://highlightjs.org/
License: see project LICENSE
Touched: 2021
*/
* {
margin: 0;
padding: 0;
}
.con {
display: flex;
width: 90%;
margin: 0 auto;
justify-content: space-between;
}
.con div {
width: 48%;
}
.btnbox {
width: 100%;
text-align: center;
}
.btn {
display: inline-block;
}
.left {
margin-top: 20px;
}
pre code.hljs {
display: block;
overflow-x: auto;
padding: 1em;
}
code.hljs {
padding: 3px 5px;
}
.hljs {
background: #f3f3f3;
color: #444;
}
.hljs-comment {
color: #697070;
}
.hljs-punctuation,
.hljs-tag {
color: #444a;
}
.hljs-tag .hljs-attr,
.hljs-tag .hljs-name {
color: #444;
}
.hljs-attribute,
.hljs-doctag,
.hljs-keyword,
.hljs-meta .hljs-keyword,
.hljs-name,
.hljs-selector-tag {
font-weight: 700;
}
.hljs-deletion,
.hljs-number,
.hljs-quote,
.hljs-selector-class,
.hljs-selector-id,
.hljs-string,
.hljs-template-tag,
.hljs-type {
color: #800;
}
.hljs-section,
.hljs-title {
color: #800;
font-weight: 700;
}
.hljs-link,
.hljs-operator,
.hljs-regexp,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-symbol,
.hljs-template-variable,
.hljs-variable {
color: #ab5656;
}
.hljs-literal {
color: #695;
}
.hljs-addition,
.hljs-built_in,
.hljs-bullet,
.hljs-code {
color: #397300;
}
.hljs-meta {
color: #1f7199;
}
.hljs-meta .hljs-string {
color: #38a;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: 700;
}
.btn,
.btn-all {
margin-top: 10px;
display: inline-block;
color: #0099cc;
background: #2e7eee;
border-radius: 10px;
text-decoration: none;
text-transform: uppercase;
border: none;
color: white;
padding: 8px 16px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
transition-duration: 0.4s;
cursor: pointer;
}
#myTextarea {
width: 100%;
height: 500px;
}
五、完成
index.js
// 定义正则
let reg = /^\{\{(.+)\}\}$/; // 匹配{{..}}
let repeatReg = /^\{\{repeat\(\d+(,\d+)?\)\}\}$/; // 匹配{{repeat(n)}}和{{repeat(n,m)}}
let boolReg = /^\{\{bool\(\)\}\}$/; // 匹配{{bool()}}
let integerReg = /^\{\{integer\(\d+,\d+\)\}\}$/; // 匹配{{integer(n,m)}}
let objReg = [boolReg, integerReg]; // 对象里会用到的所有正则
// 判断value是否符合objReg中的规则
function isConformObjReg(value) {
return objReg.find((r) => r.test(value));
}
// 随机生成布尔值的函数
function bool() {
return Math.random() < 0.5 ? true : false;
}
// 生成n到m之间的随机整数(包含n和m)
function integer(n, m) {
return Math.floor(Math.random() * (m - n + 1) + n);
}
// 获得需要重复的次数,次数在n到m之间,没传递m时次数为n
function repeat(n, m) {
if (!m) return n;
return integer(n, m);
}
/*
* @param {*} 左侧输入框输入的值转化成的 js 数据
* @return {*} 根据传入的数据生成对应的 js 格式数据
*/
let generateData = (data) => {
// TODO:待补充代码
if (typeof data !== "object") {
// 如果data是基础数据类型,不做处理
return data;
}
// 到这里说明data一定是object类型的
let result; // 存放结果
if (Array.isArray(data)) {
// 如果data是数组
result = [];
if (repeatReg.test(data[0])) {
// 数组第一项是{{repeat(...)}}
// 获得需要重复的次数
const nums = eval(reg.exec(data[0])[1]);
for (let i = 0; i < nums; i++) {
// 以数组第二项为基准生成数据,递归调用generateData
result[i] = generateData(data[1]);
}
} else {
// 数组第一项不是{{repeat(...)}},则直接遍历数据对数组每一项进行generateData处理
for (let i = 0; i < data.length; i++) {
result[i] = generateData(data[i]);
}
}
} else {
// 如果data不是数组那就是对象
result = {};
for (const key in data) {
const value = data[key];
if (isConformObjReg(value)) {
// 属性值是{{bool()}}或{{integer(...)}}
// 获得{{和}}之间的匹配的结果,如:"bool()"或"integer(...)""
const fnStr = reg.exec(value)[1];
// 用eval将fnStr字符串当作js代码来运行,如果fnStr为"bool()"则 eval(fnStr)代表运行bool函数
result[key] = eval(fnStr);
} else if (typeof value === "object") {
// 属性值不符合对象允许的正则规则并且属性值是object类型,则递归调用generateData
result[key] = generateData(value);
} else {
// 属性值不符合对象允许的正则规则并且属性值不是object类型,则属性值是基础数据类型,不做处理
result[key] = value;
}
}
}
return result;
};
module.exports = { generateData };