`

改进一下Array.forEach方法。

阅读更多
Ruby能轻易实现的一个功能在JavaScript里用不了,比较让人郁闷:
[1,2,3,4,5].each{|item| puts item; break if item > 3;}

1.6版本的JavaScript为Array实现了一个forEach方法,在MooTools中它有个alias叫each,但用起来不是那么方便,好像没有办法实现上面ruby代码的功能。
[1,2,3,4,5].forEach(function(item){
    alert(item);
    if(item>3) //return?没效果,只是跳出这个匿名function而已,本来代码就已经执行完了,加个return明显多余。break?没有这样用的。
});

仔细一想,反正这个匿名函数的返回值也没有用处,不如直接用作判断跳出循环的条件吧,于是写出如下代码:
Array.prototype.forEach = function(fn, bind){
	for(var i=0; i<this.length; i++){
		var result = fn.call(bind, this[i], i, this);
		if(result!==undefined && !result) break;
	}
};

使用:
example 1
[1,2,3,4,5].forEach(function(item){
	alert(item);
});

example 2
[1,2,3,4,5].forEach(function(item, index, arr){
	alert('数组['+arr+']的第'+(index+1)+'个元素是'+item);
	return item<=3;//返回false则跳出循环
});
分享到:
评论
5 楼 RednaxelaFX 2009-08-22  
def foo
  [1,2,3,4,5].each {|item| puts item; break if item > 3;}
end

这种写法里,block就是一个匿名函数,在其内部的跳转自然是局部跳转,但block里的break是跳转到block之外的,就是一个非局部跳转。
想像一下一般函数调用栈的状况。如果调用了foo,在block中执行的时候,调用栈的状况如下:
frame for `block' // stack top
frame for Enumerable#each
frame for foo
// ...other frames

如果是局部跳转,那么调用栈的结构不需要有任何变化。但对非局部跳转来说,跳到函数外了,那对应的栈帧也该消失了。于是执行break之后,调用栈会变成这样:
frame for foo // stack top
// ...other frames

不光是block的栈帧,连Enumerable#each的栈帧被break也一口气消了。这跟普通的break的局部跳转语义不同,跟return也不同。非局部跳转要没有语言直接支持的情况下要实现都挺烦的……Java里的惯用法是抛合适的异常来实现这类跳转。
4 楼 yuan 2009-08-22  
晕,我试了一下for in
for(var i in a)
  document.write(i);

输出的这个i还不是数组a的内容,而是它的每个下标,那我觉得还不如直接
for(var i=0; i<a.length, i++)


p.s:FX说的我看得稀里糊涂的……哈哈
3 楼 yuan 2009-08-22  
全冠清 写道
感觉还不如for in来的直接

for in遍历数组好像会有副作用吧?
2 楼 全冠清 2009-08-16  
感觉还不如for in来的直接
1 楼 RednaxelaFX 2009-07-22  
这就是要求在JavaScript里实现非局部跳转语义(non-local jump semantics)。当然JavaScript的function是不支持非局部跳转的,所以只能想办法模拟。我想起了这系列的文:http://community.bartdesmet.net/blogs/bart/archive/2009/07/12/bart-s-control-library-not-what-you-think-it-is-part-1.aspx,例子是C#的,不过要解决的问题类似,都是非局部跳转。

相关推荐

Global site tag (gtag.js) - Google Analytics