Note that this question focuses on comparing if two functions come from the same function definition. Not a general comparison of two objects (e.g. array, dates) in javascript.
In an example code like this:
function father(num) {
function generateChild() {
console.log(num);
}
return generateChild;
}
const child1 = father(1);
const child2 = father(2);
// Tests:
console.log(child1 == child2); // false
console.log(child1 === child2); // false (as expected)
console.log(child1.prototype===child2.prototype); // false
console.log(child1.prototype.constructor===child2.constructor.prototype); // false
console.log(Object.getOwnPropertyDescriptor(child1.prototype, 'constructor').value === Object.getOwnPropertyDescriptor(child2.prototype, 'constructor').value); // false
console.log(child1.toString() == child2.toString()); // true.
How can I know that child1
and child2
are the same generateChild function?
Even though the toString()
example works. I don’t want to use toString here. Two functions could match their toString()
value but be defined with the same code in two different places, thus, they are two different functions that happen to have the same code. e.g.:
function test(){console.log('test')}
function test(){console.log('test')}
test1.toString() === test2.toString()
// this is true. but they are not really the same function as in the case of generateChild
Notice that this is specially complicated since the function is defined inside another function and runs in a closure. There are simple ways to compare functions such as Array.prototype.map === Array.prototype.map
. This is true for example, but it is not the same case.
It is also interesting to note, that the browser devtools knows they have the same constructor defined in the same place. Constructors in the devtools seem to have a [[FunctionLocation]]
that it is not available in runtime.
Note about object comparison and other questions:
Other questions such as How can I determine equality for two JavaScript objects? and similar focus on comparing two objects e.g. compare {a:1} == {a:1}
or [1,2] == [1,2]
which can be compared using key/value comparison or iterating through values, but this is something that can’t be done with functions.
Though very similar, tt differentiates from Javascript comparing if 2 functions are exact same because this function is defined inside another function.
3
Answers
Some option could be compare 2 stack traces if an error is thrown inside a function.
If a function accepts argument we could provide a throwing argument.
Maybe somebody knows a better way how to throw the error.
It sounds like you want to know if the function came from the same source code.
This is impossible to accomplish as not all JavaScript platforms can guarantee a unique identifier for source code origin. For example, the JavaScript engine itself can compile a function from a string at runtime using
eval
raising questions as to where the source code came from. Witheval
specifically, it may get marked with the location of theeval
call that generated it, not somehow the location of where the source code string got its value, which doesn’t even make sense if it’s not a string literal in code somewhere.I think the closest thing you can get is to peel off the location of the code from the stack trace of an
Error
as explained in answers to this question. And then, since functions are objects, you can manually add a property that you will use to test the equivalence of two functions. This of course only works for functions that you have specifically vetted and manually define their origin. In situations where the stack trace doesn’t provide a sufficiently unique identifier, you can manually tag any function with an appropriate unique identifier.The code might look something like this:
If performance is an issue then just tag it manually
generateChild.equivalenceId = 'someUniqueString'
This is more of a hack but it was fun to implement, the idea is to make the function to throw an exception and then extract the line number from the exception stack trace. the script accomplish this by passing parameters where the valueOf method throws an exception.
The line number corresponds to the place where the exception was thrown not where the function was defined. but given that they are from within the function it will tell you that in fact the two are from the same function.
this will only work if the function meet the following conditions:
The script uses a regex to extract the information, it may fail if the stack trace is in another format. It includes two regex for chrome and firefox