web-dev-qa-db-ja.com

JavaScriptで関数の同等性をテストする方法

どのようにして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/

22
Jamie Fearon

toStringを呼び出した結果を比較することで、2つの関数の内容が正確にであるかどうかを確認できます

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

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

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

ただし、異なる文字が1つしかない場合は失敗します。一方、2つの関数doが同じかどうかを確認することは、ほとんど不可能です。

27
Alex Turpin

問題は、関数の平等の概念が異なることです。

  • 参照の等価性。関数はメモリのどこかに保存され、特定のアドレスから始まります。 2つの関数名(基本的には内部のアドレス)の場合、参照の等価性は、両方の名前が同じアドレスを指す場合に限りtrueを提供します。 1つを割り当てるときは問題ですbar = foo。 JavaScriptでは参照の等価性が使用されます。
  • 別の回答で提案されているソースコードの平等。関数本体の文字を変更すると機能しません。また、toSourceはW3C標準化されていないため、現在(2014年現在)Firefoxでのみ利用できます。
  • ソースコードの構文上の同等性。抽象構文ツリーを使用して、スペースやコメントの変更を防ぐことができます。ラムダ計算で定義されているように、アルファ同等性(つまり、変数の名前が一貫して変更される関数の同等性)を使用できますが、
  • Extensional equality 、同じように機能する場合に関数が等しい場合。 a theorem は、関数の拡張等価性をチェックするアルゴリズムが存在しないことを示しているため、探しているものではありません。ただし、JSよりもいくつかの高度な言語では
  • 意図的な同等性(関数が手動で同等であること、またはプログラムがコンパイルされないことを証明する場合)および
  • 観測的等式( これは説明するには高度すぎる )。

だから、あなたが平等であると考えるものに注意してください。

21
polkovnikov.ph

イベントのNode.jsソースを見る場合

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

コアチームが_===_を使用して関数が等しいかどうかを比較していることがわかります。

関数に_===_がどのように実装されているかはわかりませんが、2つの異なる関数が同じtoString()結果を返す可能性があるため、toString()ではないことを望みます。

4
Alexander Mills

2つの変数referがまったく同じ関数オブジェクトであるかどうかをテストし、関数を文字列に変換して、それらが本当に正確に同じですが、2つの関数がまったく同じことを実行するかどうかを判断しようとすると、少し難しくなるか、かなり難しくなります。

ミニファイアはかなりの量の静的分析を行うため、ミニファイアを介して関数のペアを実行すると興味深いでしょう。

3
Pointy

この機能が必要な場合は、プログラムを少し再構成した方がよいかもしれません。このような何かがうまくいくかもしれません:

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
1
BLSully

基本的に、それは一般的に不可能です。 JavaScriptで機能の等価性をテストする方法はありません。あなたが得ることができる最も近いものは、それらのコードを文字列として比較して等しいかどうかです。

0
m4573r

シンプルなアプローチ:サブスクライブAPIを実装して、呼び出されるたびに一意のIDを返す場合、そのIDを使用してサブスクライブ解除APIを呼び出すのと同じくらい簡単です。内部的には単純なシナリオでは、単純な配列を使用してすべてのサブスクライバーを格納しますが、このアプローチでは格納する必要があります。 IDは、サブスクライブコールを1回実行するたびに増加できる単純なカウンターにすることができます。

{ID:サブスクライバーのコールバック関数}

したがって、すべてのサブスクライバーにパブリッシュする場合は、すべてのサブスクライバーを反復処理します。

高度なアプローチ:サブスクライブAPIで単純な関数名を受け入れる代わりに、onMessage関数(またはこのメソッドに付けたい名前)を持つクラスのオブジェクトを受け入れます。その後、同じオブジェクトのインスタンスを登録解除APIに渡すだけで、自分の登録を解除できます。サブスクライバーに通知する必要がある場合は、すべてのサブスクライバーのinstance.onMessage関数を呼び出すことができます。 2つのオブジェクト参照を比較するのは簡単です。

0
TechMaze