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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12216540/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 07:25:17  来源:igfitidea点击:

How to test for equality of functions in Javascript

javascriptfunctionequality

提问by Jamie Fearon

How would I get a positive test for bar and foo's equality?

我如何才能对 bar 和 foo 的相等性进行阳性测试?

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

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

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

Both the above conditionals are false.

以上两个条件都是假的。

Updated - As requested the reason I need to test for function equality

更新 - 根据要求,我需要测试函数相等性的原因

I am building a Publish/Subscribe framework and need to pass the callback inorder to unsubscribe to a topic.

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

Please see the fiddle: http://jsfiddle.net/jamiefearon/hecMS/47/

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

回答by Alex Turpin

You could check whether the content of two functions is exactlythe same by comparing the result of calling toStringon them

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

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

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

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

That will, however, fail if there is but one character that is different. Checking to see if two functions dothe same thing, on the other hand, is pretty much impossible.

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

回答by polkovnikov.ph

The problem is that there're different notions of equality on functions.

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

  • Reference equality. Functions are stored somewhere in memory, and start from a certain address. For two function names (which are essentially addresses inside) reference equality gives you trueiff both names point to the same address. It's a matter when you assign one bar = foo. Reference equality is used in JavaScript.
  • Equality on source code as proposed in another answer. It won't work, if you change any character in function body. Also, toSourceis currently (as of 2014) only available in Firefox, as it's not W3C standartized.
  • Syntactic equalities on source code. One could use abstract syntax trees to resist against modifications in spaces and comments. One could use alpha-equivalence (i.e. equivalence of functions, where variables are consistently renamed) as defined in lambda calculus, but also there is
  • Extensional equality, when functions are equal if they work the same way. There's a theoremstating that there's just no algorithm to check for extensional equality of functions, so it's certainly not the one you're searching for. Though, in some more advanced languages than JS there are
  • Intensional equality (where you either prove that functions are equal by hand or your program doesn't compile) and
  • Observational equality (this one is too advanced to explain).
  • 引用相等。函数存储在内存中的某处,并从某个地址开始。对于两个函数名称(本质上是内部地址),引用相等性为您提供了true两个名称都指向相同地址的条件。当您分配一个时,这是一个问题bar = foo。JavaScript 中使用引用相等性。
  • 另一个答案中提出的源代码平等。如果您更改函数体中的任何字符,它将不起作用。此外,toSource目前(截至 2014 年)仅在 Firefox 中可用,因为它不是 W3C 标准化的。
  • 源代码的句法相等性。人们可以使用抽象语法树来抵制空格和注释中的修改。可以使用 lambda 演算中定义的 alpha 等价(即函数的等价,其中变量始终重命名),但也有
  • 外延相等,当函数以相同方式工作时相等。有一个定理指出,没有算法可以检查函数的外延相等性,因此它肯定不是您要搜索的算法。虽然,在一些比 JS 更高级的语言中,有
  • 内涵相等(您要么手动证明函数相等,要么您的程序无法编译)和
  • 观察平等(这个太高级了,无法解释)。

So, take care of what you think equality is.

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

回答by Alexander Mills

If you look at the Node.js source for events

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

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

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

you can see that the core team uses ===to compare functions for equality.

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

I am not sure how ===is implemented for functions, but I sure hope it's not toString(), since two different functions might have the same toString()result.

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

回答by Pointy

You can test to see whether two variables referto the exact same function object, and you can convert functions to strings and see if they're really exactly the same, but trying to determine whether two functions do the exact same thingwould be a little harder, or maybe a lot harder.

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

Running a pair of functions through a minifier would be interesting, because minifiers do a considerable amount of static analysis.

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

回答by BLSully

It seems like if you need this functionality, it might be better to restructure your program a bit. Something like this could work:

似乎如果您需要此功能,最好稍微重组您的程序。这样的事情可以工作:

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

回答by m4573r

Basically, it's impossible in general. There is no way to test functional equality in javascript. The closest you can get is either compare their code as string for equality.

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

回答by TechMaze

Simple approach: If you implement your subscribe API to return a unique ID every time it is invoked, then it will be as simple as invoking unsubscribe API with that ID. Internally in simple scenario you would use a simple array to store all subscribers but with this approach you will have to store. An ID can be a simple counter that you can increment with every single subscribe call.

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

{ID: subscriber' callback function}

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

So iterate over all subscribers when you want to publish to all subscribers.

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

Advanced approach: Instead of accepting a simple function name in subscribe API, accept an object of a class which should have an onMessage function (or whatever name you want to give this method). Then you can simply pass same instance of object to unsubscribe API to get yourself unregistered. When you need to notify subscriber you can invoke instance.onMessage function of all subscribers. Comparing two object reference is easy.

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