Array 方法综合判断题目必填项是否为空

判断题目必填项是否为空

originalQuestions 数组存放着访谈题目列表(目前共有 18 道),数据格式如下:

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
38
39
40
41
42
var originalQuestions = [	// 简答题
{
content: "请简单介绍一下您的经历(包括部门、岗位、司龄、曾任职的公司和岗位等)?", // 题目
id: "f9912584095a694c9f9882518c4e9da350b6", // 题目 ID
choices: [], // 选项
isShow: 1, // 是否显示(主要用于跳题)
maxChoices: 0, // 最大可选多少个选项
minChoices: 0, // 最少可选多少个选项
number: 1, // 题目序号
required: true, // 是否必填
type: 2, // 题型:
}, // 判断题
{
content: "您是否是部门负责人?",
id: "9d5a5f98799b0743d608b7f2eb1d0e338b84",
choices: [
{
content: "是",
id: "1b5366a873ddaf43a08b4fdfef9e133d72d2",
isExclude: 0,
jumpNumber: 7,
number: 1,
required: false,
type: 0,
},
{
content: "否",
id: "6c8c368b15998e4798d89f47d35127559631",
isExclude: 0,
jumpNumber: 8,
number: 2,
required: false,
type: 0,
}
],
isShow: 1,
maxChoices: 0,
minChoices: 0,
number: 6,
required: true,
type: 0,
}];

访谈题目分为两种:一种是简答题,另一种是判断题。在这里需要根据题目的 required 属性来确定题目是否必填。

通过请求处理得到的响应数据为一个数组,数组当中的每个对象对应着一个用户的访谈填写详情。对象中的前四个属性是用户基本信息,并非用户访谈题目的填写答案,最后五个属性也是如此,只有中间那部分才是用户作答的完整信息,即 list[userIndex][4] 才是用户填写的第一道题的答案。

另外,用户也并非每道题都有作答。例如,当用户没有作答第二道题,那么对象就不会存在 “5” 属性。

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
var list = [	{
"0": "肖 AA",
"1": "前端",
"2": "前端",
"3": "高",
"4": 222,
"7": 2222,
"9": "是",
"10": 333,
"name": "肖 AA",
"department": "前端",
"job": "前端",
"level": "高",
"_XID": "row_86"
}, {
"0": "肖 BB",
"1": "前端",
"2": "前端",
"3": "高",
"4": 222,
"5": 2222,
"6": 2222,
"7": 2222,
"8": 2222,
"9": "是",
"10": 333,
"name": "肖 BB",
"department": "前端",
"job": "前端",
"level": "高",
"_XID": "row_26"
}];

在这里,我们需要对用户作答情况进行处理,检测是否存在用户没有作答必填项。一旦发现存在,直接返回该用户的 index 以及未作答题目的序号。

① 检测单个用户

在这里先只对一个用户对象进行检测,即:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var obj = {
"0": "肖 AA",
"1": "前端",
"2": "前端",
"3": "高",
"4": 222,
"7": 2222,
"9": "是",
"10": 333,
"name": "肖 AA",
"department": "前端",
"job": "前端",
"level": "高",
"_XID": "row_86"
}

至于要从用户答案还是题目列表开始遍历,很显然,因为要判断用户有无漏答题目,所以应从 originalQuestions 开始。

第一版( forEach 实现)

实现思路

通过 forEach 来遍历题目列表,当题目的 required 为 true 且用户对应题目的作答情况为空时,则标记好信息后直接 return 跳出循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var isFalse = false; // 用户是否没有作答必填题
var pos = -1; // 用户未作答题目的序号

// 第一版检测函数
function determine0(obj) {
originalQuestions.forEach((item, index)=> {
if(item.required && !obj[String(index + 4)]) {
this.isFalse = true;
this.pos = index;
console.log(`pos:${index}`);
return;
}
})
}
determine0(obj);

输出结果

1
2
3
4
5
pos:1
pos:2
pos:4
pos:7
pos:8

存在缺陷

  • 打印输出多次,这说明 return 并没有跳出循环。查阅资料后发现,forEach 循环不能被 return 终止,其作用和 for 循环中的 continue 相似,只是跳出当前循环,并继续执行之后的循环。同样,在 forEach 中也不能使用 break、continue 来跳出循环。

第二版( findIndex 实现)

实现思路

数组的 findIndex 方法会根据 return 返回的条件进行遍历查找,一旦发现数组中有匹配的元素,就直接返回该元素的 index。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 第二版检测函数
function determine1(obj) {
this.pos = originalQuestions.findIndex((item, index)=> {
if(item.required && !obj[String(index + 4)]) {
console.log(`pos:${index}`);
}
return item.required && !obj[String(index + 4)];
})
if(this.pos !== -1) {
this.isFalse = true;
}
}
determine1(obj);

输出结果

1
pos:1

② 检测所有用户

当检测所有用户时,所需要采用的策略与检测单个用户时大有不同。仍旧是先遍历谁的问题,这次该从用户列表还是从题目列表开始遍历?这里采用的是,先从题目列表中遍历。当抽出一道题时,再从用户列表中依次抽取用户来比对是否作答该题目。

基础

实现思路

因为要对所有用户依次进行题目列表的遍历,但真正需要遍历的题目只有必选题,所以为了提高效率,需要先通过数组的 filter 方法把题目列表筛选成只含有必答题的题目列表。

得到精简后的题目列表后,通过使用数组的 some 方法来判断是否存在用户未作答题目。当存在时,some 方法的返回结果为 true,否则返回 false。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var row = -1;
var column = -1;

// 基础版
function determineAll0(list) {
var newQuestions = questions.filter(item => item.required);
var a;
var result;
return newQuestions.some(item => {
for(a=0; a<list.length; a++) {
result = list[a][String(item.number + 4)];
if(!result) {
this.row = a;
this.column = item.number;
console.log(`row: ${this.row}, col:${this.column}`);
}
return !result;
}
})
}
this.isFalse = determineAll0(originalList); // true

输出结果

1
row: 0, col:1

存在缺陷

  • 不够精简

简化版

基础的 for 循环操作有些繁琐,数组的 filter 和 some 方法可以合并。对代码进行简化如下。

1
2
3
4
5
6
7
8
// 简化版
function determineAll1(list) {
return questions.filter(f => f.required).some(question => {
this.column = question.number
this.row = list.findIndex(user => !user[String(question.number + 4)])
return this.row !== -1;
})
}

娱乐版

经过试验,最后将代码化简至 3 行。

1
2
3
4
// 娱乐版
function determineAll2(list) {
return questions.filter(f => f.required).some(s =>(this.row = list.findIndex(i => !i[(this.column = s.number) + 4])) + 1)
}