如何在Javascript中测试函数的相等性

时间:2012-08-31 13:39:16

标签: javascript function equality

如何才能对bar和foo的平等进行积极的测试?

 foo = function() {
    a = 1;
 }; 

 bar = function() {
    a = 1;
 }; 

 if (foo === bar) alert('baz');
 if (foo == bar) alert('qux');

以上条件都是假的。

更新 - 根据要求我需要测试功能相等性的原因

我正在构建一个发布/订阅框架,需要传递回调才能取消订阅主题。

请看小提琴:http://jsfiddle.net/jamiefearon/hecMS/47/

7 个答案:

答案 0 :(得分:24)

您可以通过比较调用toString的结果来检查两个函数的内容完全是否相同

 var foo = function() {
    a = 1;
 }; 

 var bar = function() {
    a = 1;
 }; 

alert(foo.toString() == bar.toString());​
然而,如果只有一个不同的角色,那将会失败。另一方面,检查两个函数是否相同的事情几乎是不可能的。

答案 1 :(得分:19)

问题在于功能上存在不同的平等概念。

  • 参考平等。函数存储在内存中的某个地方,并从某个地址开始。对于两个函数名称(基本上是内部地址),如果两个名称都指向相同的地址,则引用相等性会为您提供true。当你指定一个bar = foo时,这是一个问题。 JavaScript中使用引用相等。
  • 另一个答案中提出的源代码平等。如果更改函数体中的任何字符,它将无法工作。此外,toSource目前(截至2014年)仅适用于Firefox,因为它不是W3C标准化的。
  • 源代码的句法等同。可以使用抽象语法树来抵制空格和注释中的修改。可以使用lambda演算中定义的alpha等价(即函数的等价,其中变量一致地重命名),但也有
  • Extensional equality,当函数相同时,如果它们以相同的方式工作。有a theorem表示没有算法可以检查函数的扩展相等性,所以它肯定不是你要搜索的那个。虽然,在一些比JS更高级的语言中有
  • 内涵相等(您可以手动证明函数是相等的,或者程序不能编译)和
  • 观察平等(this one is too advanced to explain)。

所以,请注意你认为平等的事情。

答案 2 :(得分:4)

如果您查看Node.js事件来源

https://github.com/nodejs/node/blob/master/lib/events.js

您可以看到核心团队使用===比较函数是否相等。

我不确定===是如何为函数实现的,但我确定它不是toString(),因为两个不同的函数可能会有相同的toString()结果。

答案 3 :(得分:3)

您可以测试两个变量是否将引用到完全相同的函数对象,并且您可以将函数转换为字符串并查看它们是否真的完全相同,但是尝试确定是否两个函数完全相同的事情会更难,或者可能更难。

通过缩小器运行一对函数会很有趣,因为缩小器会进行大量的静态分析。

答案 4 :(得分:1)

似乎您需要此功能,可能会更好地重构您的程序。这样的事情可以奏效:

function baz(myInt) { return 3 + myInt; }
function asd(a) { return 3 + a; }

var foo = baz;
foo(1); //returns 4

var bar = baz;
bar(3); //returns 6

foo === bar; //true

bar = asd;
bar(3); //returns 6

foo === bar; //false

答案 5 :(得分:0)

基本上,一般来说,这是不可能的。没有办法在javascript中测试功能相等。你可以得到的最接近的是将它们的代码作为字符串进行比较。

答案 6 :(得分:0)

简单方法:如果您实现订阅API以在每次调用时返回唯一ID,那么它就像使用该ID调用unsubscribe API一样简单。在内部简单的场景中,您将使用一个简单的数组来存储所有订阅者,但是使用这种方法您将不得不存储。 ID可以是一个简单的计数器,您可以在每次订阅调用时递增。

{ID:订阅者'回调函数}

当您想要发布给所有订阅者时,请遍历所有订阅者。

高级方法: 不接受订阅API中的简单函数名,而是接受应该具有onMessage函数的类的对象(或者您希望为此方法提供的任何名称)。然后,您可以简单地将相同的对象实例传递给取消订阅API,以使您自己取消注册。当您需要通知订阅者时,您可以调用所有订阅者的instance.onMessage函数。比较两个对象引用很容易。