一. 引子
今天遇到个问题,如何在遍历数组的同时动态地删除元素。接下来我将试图从遍历和删除两个方面做出代码解释并最终分析效率问题。
二. 遍历数组
先来看看示例数组。
var a1 = [];
a1[1] = 'aa';
a1[5] = 'bb';
console.log(a1.length);//6
方式一,用6次循环遍历 a1 中仅有的两个数据,四次输出
var l1 = a1.length; for(var i = 0; i < l1; i++) { console.log('a1[' + i + ']=' + a1[i]); }
输出方式二a1[0]=undefined a1[1]=aa a1[2]=undefined a1[3]=undefined a1[4]=undefined a1[5]=bb
var k = -1;
for(k in a1)
{
console.log('a1['+ k + "]=" + a1[k]);
}
输出
a1[1]=aa a1[5]=bb
三. 删除元素
方式一. 使用splice函数
对于表达式 a1.splice(1,1) ,后面的 1 表示 删除 a1 的一个元素,前面的 1 表示从下标为 1 的地方开始删,被删除的元素后面的元素的下标都会相应地减一。可以想见,执行 a1.splice(1,5)会导致 a1[1] 和 a1[5] 都被删除掉。
var a2 = a1.splice(1,1);
for(k in a1)
{
console.log('a1['+ k + "]=" + a1[k]);
}
输出
a1[4]=bb
注意到原来是 a1[5] = bb 现在,下标减小了,这也许不是你想要的。
a2[0]=aa
使用 splice 的缺陷据说是 IE5.5 不支持,暂时就不查证了。
方式二. 配合使用 slice 和 concat 函数
网络上有种做法, 自定义原型函数 Array.prototype.del ,修改 Array 原型的做法,不可取。一方面,修改 JS 原生类型的 原型本身就应该避免;另一方面,我发现,这么做会影响使用 for in 遍历数组的结果。例如:
var a3 = [1,2];
Array.prototype.someFunc = function(){
//some commands
return ;
};
for(var k in a3)
{
console.log('a3[' + k + ']='+ a3[k]);
}
输出
a3[0]=1 a3[1]=2 a3[someFunc]=function (){ //some commands return ; }
这不是我们想要的结果。
所以,最终给出的方法是这样的:
function delEle(aIn,iIdx)
{
if(! Array.prototype.isPrototypeOf(aIn)){
return null;//根据Null可以判断本次调用失败
}
var iIdx = parseInt(iIdx),
iLen = iIdx.length;
if(iIdx < 0 || iIdx >= iLen){
return null;//根据Null可以判断本次调用失败
}
var aRet = [];//与NULL不同
return aRet=aIn.slice(0,iIdx).concat(aIn.slice(iIdx+1));
}
四.在遍历的过程中选择性删除
我的做法是,把要删除的元素设置为 undefined ,遍历完了之后再过滤出非 undefined 的元素,拼成新的数组。