John Resig不久前发表了一个非常非常非常smart的函数,为javascript的数组加入了一个remove方法,
Javascrip Arrray RemoveJohn Resig是mozilla公司的成员,jQuery的founder和主要奉献者,非常非常smart的一个人,真的是把编程当成了一项艺术。
这个函数的代码如下:
// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};整个函数的执行代码只有三行。可以用来从一个数组中删除某些值,两个参数分别是从第几个值删除到第几个值,可以为负,负就是倒数第几个值。
其中有三个很smart的地方。
第一,this.length ,一般我们写出来的remove函数是,截头、截尾、连接头尾。如下:
array = array.slice(0,i).concat( array.slice(i+1) );John版本利用了控制array.length来截头,少了一次slice操作。改变length的值比调用slice方法消耗小得多。
第二,john版本利用了array.push来连接数组,没有用concat,据他的介绍,concat会做这三件事:
1) Create a new array
2) Copy all the items from the first array into the new array
3) Copy all the items from the second array into the new array
所以concat不管从cpu上,还是内存的消耗上,都是极度不推荐的
第三,也是整个函数最精彩的地方,就这一行
var rest = this.slice((to || from) + 1 || this.length);我们可以看到一行程序到底可以做些什么事情,(to || from) + 1 || this.length 这一段的意思是说:取到to的数值加上1(这是最普遍的情况,比如,删除从1到3的元素,那么,得到4,4以及4以后的元素为尾),如果to为undefined(只删除from位置上这个元素),那么from+1及from+1以后位置的元素为尾。后半部分的 || this.length 是说,如果得到的尾开始标记为0(不过是to还是from中得到的,不管是从倒数第一位开始截还是截到倒数第一位,尾都应该为空),则将尾的标记标记为数组长度,因为slice接受0参数的时候,会返回整个数组。
如上,就是这个函数的巧妙之处。不过我认为,这个函数还是有小小的两个地方值得修正:
1,array.remove(1)的含义等同于array.remove(1,1),这与通常的习惯不服,通常的省略to参数的含义应该是从from的地方删除直到结尾。(不过,John好像是故意要如此实现,上面讲到的第三点的trick也就在此了,所以,我觉得这样还是有意义的,删除的结尾的我们可以用remove(1,-1)来实现,而remove(1)比remove(1,1)更加elegant一点)
2,函数缺少必要的合法性检查,比如to的位置是否在from之前,from和to的位置是否超出了array.length,导致传递某些参数组合的时候,会让remove后的数组变长( 如array.remove(3,1) )
所以,我也加入了一点小小的修正,如下
// Array Remove - By stauren@stauren.net (MIT Licensed)
// Based on John Resig's Array Remove (MIT Licensed)
Array.prototype.remove = function(from, to) {
var rest, len=this.length;
from = from<0 ? from-0+len : from;
to = to<0 ? to-0+len : to;
if (to<from || from>=len || to>=len) {
return false;
}
rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};最后,用John Resig的一段话来结尾吧,我爱这么艺术的coding!!
This is one thing that I really like about JavaScript: You can write a three line function for a trivial operation and still need 800 words to explain its true nature. Comments and feedback are appreciated.