how do I compare 2 functions in javascript

How do I compare 2 functions in javascript? I am not talking about internal reference. Say

var a = function(){return 1;};
var b = function(){return 1;};

Is it possible to compare a and b ?

Answers:

Answer
var a = b = function( c ){ return c; };
//here, you can use a === b because they're pointing to the same memory and they're the same type

var a = function( c ){ return c; },
    b = function( c ){ return c; };
//here you can use that byte-saver Andy E used (which is implicitly converting the function to it's body's text as a String),

''+a == ''+b.

//this is the gist of what is happening behind the scences:

a.toString( ) == b.toString( )  
Answer

Closures mean that you need to be very careful what you mean when you say "compare". For example:

function closure( v ) { return function(){return v} };
a = closure('a'); b = closure('b');
[a(), b()]; // ["a", "b"]

// Now, are a and b the same function?
// In one sense they're the same:
a.toString() === b.toString(); // true
// In another sense they're different:
a() === b(); // false

The ability to reach outside the function means that in a general sense, comparing functions is impossible.

However, in a practical sense you can get a very long way with Javascript parsing libraries like Esprima or Acorn. These let you build up an "Abstract Syntax Tree" (AST), which is a JSON description of your program. For example, the ast your return 1 functions looks like this

ast = acorn.parse('return 1', {allowReturnOutsideFunction:true});
console.log( JSON.stringify(ast), null, 2)
{
  "body": [
    {
      "argument": {
        "value": 1,              // <- the 1 in 'return 1'
        "raw": "1",
        "type": "Literal"
      },
      "type": "ReturnStatement" // <- the 'return' in 'return 1'
    }
  ],
  "type": "Program"
}
// Elided for clarity - you don't care about source positions

The AST has all the information you need to make comparisons - it is the Javascript function in data form. You could normalize variable names, check for closures, ignore dates and so on depending on your needs.

There are a bunch of tools and libraries to help simplify the process but even so, it's likely to be a lot of work and probably not practical, but it is mostly possible.

Answer

You can compare two variables that might contain function references to see if they refer to the exact same function, but you cannot really compare two separate functions to see if they do the same thing.

For example, you can do this:

function foo() {
    return 1;
}

var a = foo;
var b = foo;

a == b;   // true

But, you can't reliably do this:

function foo1() {
    return 1;
}

function foo2() {
    return 1;
}

var a = foo1;
var b = foo2;

a == b;   // false

You can see this second one here: http://jsfiddle.net/jfriend00/SdKsu/

There are some circumstances where you can use the .toString() operator on functions, but that's comparing a literal string conversion of your function to one another which, if even off by a teeny bit that is inconsequential to what it actually produces, will not work. I can think of no situation where I would recommend this as a reliable comparison mechanism. If you were seriously thinking about doing it this way, I'd ask why? What are you really trying to accomplish and try to find a more robust way of solving the problem.

Answer

toString() on a function returns the exact declaration. You can modify jfriend00's code to test it out.

This means you can test to see if your functions are exactly the same, including what spaces and newlines you put in it.

But first you have to eliminate the difference in their names.

function foo1() {
    return 1;
}

function foo2() {
    return 1;
}

//Get a string of the function declaration exactly as it was written.
var a = foo1.toString();
var b = foo2.toString();

//Cut out everything before the curly brace.
a = a.substring(a.indexOf("{"));
b = b.substring(b.indexOf("{"));

//a and b are now this string:
//"{
//    return 1;
//}"
alert(a == b); //true.

As the others said, this is unreliable because a single whitespace of difference makes the comparison false.

But what if you're employing it as a protective measure? ("Has someone altered my function since I created it?") You may actually desire this kind of strict comparison then.

Answer

Convert function to string, then, replace line-break and space before comparing:

let a = function () {
  return 1
};

let b = function () {
  return 1
};

a = a.toString().replace(/\n/g, '').replace(/\s{2}/g, ' ');
b = b.toString().replace(/\n/g, '').replace(/\s{2}/g, ' ');

console.log(a); // 'function () { return 1}'
console.log(b); // 'function () { return 1}'
console.log(a === b); // true

b = function () {
  return 2
};

b = b.toString().replace(/\n/g, '').replace(/\s{2}/g, ' ');

console.log(b); // 'function () { return 2}'
console.log(a === b); // false

b = () => 3;

b = b.toString().replace(/\n/g, '').replace(/\s{2}/g, ' ');

console.log(b); // '() => 3'
console.log(a === b); // false

p/s: If you are using ES6, try to use let instead of var.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.