1.概述
我经常使用js中的数组来存储一些数据。然后在前段页面上提供UI让用户对数据进行更新。 问题是,当用户完成操作之后,如何得知数据的哪些部分被改变?最常用的一种方式是,事先保存数据的一个备份,通过比较备份和被修改后的数据,简称结果,来获知数据的更改信息。
2. 从最简单的开始
先考虑最简单的情况,如果用户向数组中添加或者删除了某几项,如何得知?假设备份数组是 [1,2,3],
结果数组是 [3,4]。
我们期待的结果是 增加:4,删除:1,2。
请查看下面的代码:
<html>
<head>
<script>
var a = [1,2,3];
var b = [3,4];
//为了更方便的判断数组是否包含某个元素,这里添加一个prototype方法。
Array.prototype.contains = function(element){
for(var i=0;i<this.length;i++){
if(this[i]===element){
return true;
}
}
return false;
}
function f(a,b){
var added = [],removed = [];
for(var i=0;i<a.length;i++){
if(!b.contains(a[i])){
removed.push(a[i]);
}
}
for(var i=0;i<b.length;i++){
if(!a.contains(b[i])){
added.push(b[i]);
}
}
return {
added:added,
removed:removed
}
}
//转化为string以方便查看
console.log(JSON.stringify(f(a,b)));
</script>
</head>
<body>
</body>
</html>
下面是输出结果:
{"added":[4],"removed":[1,2]}
这正是我们期待的结果。看来,也没有多难嘛。
3. 包含对象的数组
现在难度升级,考虑一下,如果数组中存储的不是1,2,3这样的数据,如果是个对象呢?
var a = [new Number(1),new Number(2),new Number(3)];
var b = [new Number(3),new Number(4)];
执行程序,发现结果是这样的:
{"added":[3,4],"removed":[1,2,3]}
呃,有点奇怪,看起来是把所有a里面的元素放到removed里,把b里面的元素放到added里。
我猜到的大概的原因,验证一下。
var n1 = new Number(1);
var n2 = new Number(1);
console.log(n1===n2);
结果是 false.
原因很明确了,因为contains方法执行的时候,统统返回false,所以a和b的所有对象都被添加到对应数组了。
如何避免这种情况呢?
学过java的同学都知道,对象的内容即使完全一样,做相等判断也是会返回false,因为判断的依据并不是根据内容,而是根据toString方法的返回值。
如果想要让对象根据自身的某些特征来做比较依据,比如这里,我们想让n1和n2按照原始类型1,2来比较,该怎么做呢?试试下面这种比较方式:
console.log(n1.toString()===n2.toString());
结果是true。
恩,看来可以着手修改之前的contains方法了。
Array.prototype.contains = function(element){
for(var i=0;i<this.length;i++){
if(this[i].toString()===element.toString()){
return true;
}
}
return false;
}
再运行,结果很满意。
看来,想要根据对象的特征来比较对象,应该通过一个方法得到对象的特征参数,比如toString,然后比较特征参数。
4.总结
貌似我们只实验了删除或者增加数组元素的情况(当然我并没有演示如何删除,增加元素)。
- 事先保存数组的备份。这里涉及到数组的深度克隆。单纯的赋值是不行的。
- 遍历备份数组,如果结果数组不包含当前元素,此元素为被删除元素。
- 遍历结果数组,如果备份数组不包含当前元素,此元素为新添加元素。
如果要细致到判断内的对象特征的修改,这个,就要在上面程序的基础上增加其他专用业务逻辑了。
如果有什么疑问,请留言。大家一起学习。谢谢。