0

I have an API that takes a function as an input, and then inside the API, the intent is to add the function to an Array if the function is not already added to the Array.

The call to the API is of the form:

myApiHandle.addIfUnique(function(){
    myResource.get(myObj);
});

The API is:

myApiHandle.addIfUnique(myFunc) {
   if (myArray.indexOf(myFunc) === -1) {
       return;
   }
// add to array
}

Now this obviously does not work as expected, since each time a new function is being passed in.

My Question is: Is there a way to pass in a function into the myApiHandle.addIfUnique call that will allow me to compare the existing functions in the array with this function that is currently passed in? The comparison should compare the function name and the object, and if both are the same, then not add the function to the array. I want to avoid adding another argument to the addIfUnique call if at all possible.

In other words, is the below possible:

myApiCall.addIfUnique (someFunc) {
}

If so, what is the someFunc. And what would be the logic inside the API to detect if the function already exists in myArray?

AshD
  • 1,066
  • 2
  • 13
  • 28
  • 2
    You can only check if the function exists like you're doing with indexOf. You could update the code calling addIfUnique to not create the same function multiple times, though. – Cory Danielson Jun 02 '16 at 05:33
  • 3
    This is basically just a bad thing to be trying to do. Solve your problem a different way. There is no way to tell if two different functions actually have the same or different execution. Certainly, if they have the exact same code, they will produce the same result, but if they have different code, it does not mean they produce different results. I'd say stop passing in local functions that are created anew each time if you want to compare them. – jfriend00 Jun 02 '16 at 05:38
  • I agree. What is the problem you are trying to solve? – Stian Standahl Jun 02 '16 at 05:41

2 Answers2

0

The same problem occurs with addEventListener and removeEventListener, where the callback must be identical (in the === sense) for removeEventListener to remove it.

As you've found, obviously if you call addIfUnique like this:

addIfUnique(function() { })

the function passed each time will be a unique object. The solution is to create the function once:

var fn = function() { };
addIfUnique(fn);
addIfUnique(fn);

A related problem occurs when the function being passed in is a method invocation, so I need to bind it:

var x = { val: 42, method: function() { console.log(this.val); } };

I want to pass a bound version of it, so

addIfUnique(x.method.bind(x));
addIfUnique(x.method.bind(x));

But again, each call to x.method.bind(x) will return a separate function. So I need to pre-bind:

var boundMethod = x.method.bind(x);
addIfUnique(boundMethod);
addIfUnique(boundMethod);
0

First of all, comparing functions is meaningless, even if two functions are literally different, they may be functionally the same.
And for your problem, you can compare whether it's exactly the same object, or you can compare it literally by using toString() function and regExp.

var addIfUnique = (function() {
  var arr = [];
  return function(func) {
    if (~arr.indexOf(func)) return false;
    var nameArr = [];
    var funcName = func.name;
    var funcRegExp = new RegExp('[^\{]+\{(.+)\}$', 'i');
    var funcStr = func.toString().match(funcRegExp);
    funcStr = funcStr && funcStr[1];
    if (!funcStr) return false;
    var strArr = arr.map(function(v){
      nameArr.push(v.name);
      return v.toString().match(funcRegExp)[1];
    });
    if (~strArr.indexOf(funcStr) && ~nameArr.indexOf(funcName)) return false;
    arr.push(func);
  };
}());
fr0m
  • 26
  • 2