hguser
hguser

Reputation: 36058

a few questions when iterator the arraylike object in javascript

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

Answers (3)

georg
georg

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

jfriend00
jfriend00

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

Rob W
Rob W

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

Related Questions