28

我如何才能对 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/

4

7 回答 7

36

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

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

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

alert(foo.toString() == bar.toString());​

但是,如果只有一个不同的角色,那将失败。另一方面,检查两个函数是否做同样的事情几乎是不可能的。

于 2012-08-31T13:44:26.853 回答
23

问题是函数有不同的相等概念。

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

所以,请注意你认为的平等是什么。

于 2014-02-10T14:38:22.670 回答
3

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

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

于 2012-08-31T13:41:07.923 回答
3

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

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

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

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

于 2016-02-26T22:05:40.653 回答
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
于 2012-08-31T13:43:24.950 回答
0

基本上,一般情况下是不可能的。无法在 javascript 中测试功能相等性。您可以获得的最接近的是将它们的代码作为字符串比较是否相等。

于 2012-08-31T13:43:13.420 回答
0

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

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

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

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

于 2014-12-29T21:13:41.123 回答