【问题标题】:How to test for equality of functions in Javascript [duplicate]如何在Javascript中测试函数的相等性[重复]
【发布时间】:2012-08-31 13:39:15
【问题描述】:

我怎样才能得到对 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/

【问题讨论】:

  • 可能你的意思是让函数返回一个值?返回一个;不见了?
  • 如果您解释为什么要这样做,它可能会帮助人们提供有用的答案和 cmets。
  • 那么你要检查两个函数的内容是否完全一样?为什么你需要这样做?
  • 尖尖的 - 我已经更新了我的答案
  • 只要您传递给unsubscribe 的回调与您传递给subscribe 的回调相同,您的小提琴应该可以正常工作。这不是大多数 JS 事件发布/订阅库的工作方式吗?这种方法有什么问题?

标签: javascript function equality


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 你是对的。完美的工作......
  • 但这也完全没用。
  • 绝对不是!它对于 lodash debounce 等功能至关重要。
  • 请注意,这可能会返回误报——如果您的函数引用在其包含范围内定义的任何变量,它们可能具有完全相同的源代码但行为不同。有关示例,请参见 this answer
  • const delayedOnSave = useCallback( debounce((val) => onSave(val), 150), [onSave.toString()] );
【解决方案2】:

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

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

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

【讨论】:

  • 如果您可以为每一个添加示例,那么这将是一个很好的答案!
【解决方案3】:

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

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

【讨论】:

  • 难度不大,但实际上是不可能的。
  • @duri 好吧,我在这里了解到,大声说出某事“不可能”是一种羞辱的好方法 :-) 但是我同意你的看法,总的来说,因为完整的静态分析像 JavaScript 这样的动态语言是不可能的。
  • 嗯,两个函数是否等价的问题与数学有关,而不是与编程有关,但您可能对stackoverflow.com/questions/1132051/…感兴趣
  • @duri 这很有趣,但我认为(可能是不正确的)访问函数的实际组成与确定两个“不透明”函数的等价问题不同。例如,当然可以说两个 JavaScript 函数,当字符串化时,每个字符都是相同的,因此在运行时的行为可以假设是一致的范围内是等价的。
  • @Pointy 我认为这是不正确的。如果您有两个逐字符相同的函数,那么它们的操作仍然可能不同,因为它们可能在静态闭包中引用变量。例如function() { return x } 将根据定义函数的范围内的 x 不同返回。
【解决方案4】:

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

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

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

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

【讨论】:

【解决方案5】:

如果您需要此功能,最好稍微重构一下您的程序。像这样的东西可以工作:

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

【讨论】:

    【解决方案6】:

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

    【讨论】:

    • 这显然不正确
    【解决方案7】:

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

    {ID: 订阅者回调函数}

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-18
      • 2011-12-24
      相关资源
      最近更新 更多