tags:

views:

101

answers:

4

I'm experimenting with functional-style Javascript and have encountered an interesting situation. I have a foreach function that takes a collection and function object:

var Utils = {};

// Applies a functor to each item in a collection.
Utils.foreach = function(collection, functor)
{
  for (var i = 0; i < collection.length; i++)
  {
    functor(collection[i]);
  }
};

This is cool. However now I want to implement another function:

// Checks if a collection contains an item.
Utils.has = function(collection, item)
{
    Utils.foreach(collection, function(obj) {
        if (item === obj) {
            return true; // How to force a return from the foreach function?
        }
    });
    return false;
};

As you can see I can't implement the "has" function because my return statement doesn't break the iteration.

Can someone recommend a solution for this problem?

+2  A: 

I guess what you want is not actually forEach, but rather some (other languages call it any). The couterpart is every (or all in other languages). You'll find an example implementation on MDC.

Ionuț G. Stan
+1  A: 

Here is something real quick and untested ( it is friday 4:50 time to go home). I'll try to test and update this post later. see if this helps:

Utils = {};
Utils.foreach = function(collection, functor) {
    loop: for (var i in collection) {
        if (functor(collection[i])) {
            alert("breaking the loop!");
            break loop;
        }
    }
};
Utils.has = function(collection, item) {
    var bolReturn  = false;
    Utils.foreach(collection, function(obj) {
        if (item === obj) {
            bolReturn = true;
            return true;
        }
        return false;
    });
    return bolReturn;
};
Utils.has({"test":""}, "");
Kenneth J
+1  A: 

You need a modification to each.

Start by modifying has:

Utils.has = function (collection, item) {
  var found = false;
  Utils.foreach(collection, function (obj) {
    if (item === obj) {
      found = true;
      return false;
    }
  });
  return found;
};

Then you need to modify forEach to end early when it gets false

Utils.foreach = function (collection, functor) {
  var prop;
  for (prop in collection) {
    if (prop.hasOwnProperty(prop)) {
      if (functor(collection[prop]) === false) {
        return;
      }
    }
  }
};
bcherry
A: 

I don't think you need to abandon your structure- why not throw and catch an error to break out of the loop?

  Utils.has= function(collection, item){
    try{
        ControlCenter.foreach(collection, function(obj){
            if(item=== obj){
                throw 'found it!'
            }
        });
    }
    catch(er){
        if(er== 'found it!') return true;
    }
    return false;
};
kennebec