Reputation: 36058
In my application,I need to do some iteration with the array-like object.
So I write a custom util method:
Util.forEach=function(iterator,callback,context){
if(iterator.length){
for(var i=0;i<iterator.length;i++){
var val=iterator[i];
callback && callback.call(context||null,val,i);
}
}
}
Then I meet some problems:
Suppose I have an array: var ary=[1,2,3,4,5];
1. how to break the loop?
For example, if I want to find if value '2' is included in the array,I may try this:
Util.forEach(ary,function(value,index){
if(value==2){
//find mached value,now I should break and return this value.
//but I can not use 'break' in this context.
}
});
2. remove value of the array when iterator
If I want to remove value '2' of the array,I may try this:
Util.forEach(ary,function(value,index){
if(value==2){
//delete it.
ary.splice(i,1);
// I wonder if this is the safe way?
}
});
Since in java we can not do this when iterate an array,it will cause the concurrency exception.
Though I run the above code without any error,but I am not sure if it is the best practice?
Upvotes: 0
Views: 235
Reputation: 214999
how to break the loop?
You're not supposed to break from forEach
. That's why it's called "for each", and not "for some". "Breakable" JS iterators are every()
(stops when the callback returns false) and some()
(stops when the callback returns true).
Looking at your code once again it makes me think you actually want an indexOf
kind of method, and not an iterator.
remove value of the array when iterator
Iterators shouldn't make any changes of the underlying array. You have to implement filter()
and use it to generate a new array.
See js iteration methods for more details.
Upvotes: 0
Reputation: 707686
The first issue can be solved by checking the return value from the callback and stopping the iteration if it returns false. Then you can stop the iteration by returning false
from the callback. Returning anything other than false
(including returning nothing) will continue the iteration. jQuery uses this return value technique to cancel the iteration in their .each()
iterator. Adding that into your code, it would look like this:
Util.forEach=function(iterator,callback,context){
if (iterator.length && callback) {
for(var i = 0; i < iterator.length; i++){
var val=iterator[i];
if (callback.call(context||window,val,i) === false) {
break;
}
}
}
}
In the MDN documentation for forEach, you can see a sample implementation.
On the second issue, this type of implementaation does not permit insertion or deletion of elements at or before the iteration point because that will cause some elements to get skipped in the iteration or some objects to get iterated multiple times. The obvious way around that would involve making a copy of the object before iterating which is not efficient when not needed.
Upvotes: 0
Reputation: 349102
Generally, you can break out from a forEach
-like method by using try
-catch
and throw
.
var value = 'Not Found';
try {
Util.forEach(ary, function(value, index) {
if(value == 2) {
throw value; //<-- Throw the found result: Terminates current forEach
}
});
} catch (found) { // Catch the thrown result
value = found;
}
Upvotes: 1