3

私は次のようなコードを持っています:

obj.foo(); // obj might, or might not have a `foo` method.

obj.fooコードでが呼び出されたときに何が起こるかをオーバーライドできるかどうかを知りたいです。次に例を示します。

obj.foo = function(){ alert ("Hello"); });
obj.onCallNonExistentMethod = function(){ // I know this is imaginary syntax
    alert("World");
}
obj.foo(); // alerts "Hello"
delete obj.foo;
obj.foo(); // alerts "World" , would TypeError without the method missing handler.

私が理解していることから、Rubyではそれはmethod_missingまたはconst_missingまたはそれに類似したものになります。

JavaScriptで存在しないオブジェクトメソッドの呼び出しで何が起こるかをオーバーライドできますか?可能であれば、どうすればよいですか?

目標は、ユーザーに提供するAPIを検証して、ユーザーがAPIを安全に使用できるようにし、エラーについてより明確に警告できるようにすることです。

4

4 に答える 4

5

2年前、ベンジャミン、あなたは行動タイピングの概念をよく理解していませんでしたか?

幸運なことに、JavaScriptでその質問を書いた後、インターフェースが構造的ではないことにすぐに気付くでしょう。また、ここで話す正確な質問を解決するライブラリを作成しただけで、決して使用しないようになります。

だから、あなたの質問に答えるために:

  • はい、これを行うことは完全に可能です。
  • あなたはおそらくあなたが与えたケースのためにすべきではありません。

どうやってするの

Proxy APIを介して本当に本当に(本当に本当に)新しいブラウザをサポートするだけでよい場合、それは完全に実行可能です。

var realObject = { foo: function(){ alert("Bar"); }); // our fooable api
var api = new Proxy({}, {
    get: function(target, name){
        if(name in target){ // normal API call
            return target[name]; 
        }
        // return whatever you want instead of the method:
        return function(){ alert("Baz"); });
    }
});
api.foo(); //alerts Bar
api.bar(); //alerts Baz
api.IWillNotBuyThisRecordItIsScratched(); // alerts Baz

したがって、ブラウザのサポートは非​​常に不安定ですが、

すべきではない理由

インターフェイスは、jshintやternjsなどの静的分析ツールで通常キャッチできる(そしてキャッチする必要がある)タイプミスなどの動作を伝達します。

タイプミスをチェックするツールは、JavaScriptでの動作を伝えるのに十分なほど強力ではありません。タイプチェックは、一般的にアンチパターンと見なされます。JavaScript、Ruby、Pythonなどの言語では、取得するタイプがわかっています。

于 2014-05-25T22:15:40.440 に答える
2

残念ながら、それは広くサポートされている方法では不可能です。最も近い方法は、すべての呼び出しにプロキシ関数を使用することです。つまり、代わりに。のfoo.bar()ようなものを使用しますfoo.invoke('bar')。ただし、これはかなり醜く、最初の「興味がない」部分で意味したことに近い可能性があります。

緩く型付けされた言語では、開発者が互換性のあるオブジェクトを渡すことを期待するのはかなり一般的です。つまり、予期しないものを渡すときにエラーが発生するのは通常は問題ありません。


ただし、幸運にもECMAScriptハーモニー機能をサポートするJSエンジンを使用できる場合(明らかにIEはサポートしていません)、プロキシオブジェクトを使用してこれを実現できます。基本的に、オブジェクトをプロキシでラップします。これにより、オブジェクトの反復、プロパティの取得、さらにはプロパティの作成など、オブジェクトに対するほとんどの操作をトラップできます。この質問に対するこの回答を参照している2つのリンクに加えて、一見の価値があるかもしれません。

于 2012-06-21T18:36:32.910 に答える
1

厳密に定義されたオブジェクトを使用している場合は、オブジェクトリテラルの代わりにカスタムオブジェクトを使用する必要があります。

function Foo(bar, baz) {
  this.bar = bar;
  this.baz = baz;
}
Foo.prototype = {
  fizz: function () {
     alert(this.bar + ' ' + this.baz + '!');
  }
};

//elsewhere
f = new Foo('Hello', 'World');
f.fizz();

次に、演算子を使用して、オブジェクトがFooインスタンスであるかどうかを確認できます。instanceof

function Buzz(foo) {
  if (foo instanceof Foo) {
    foo.fizz();
  }
}
f = new Foo('Hello', 'World');
Buzz(f);

オブジェクトに特定のパラメータの関数が含まれているかどうかを確認するだけの場合は、次のようなものを使用できます。

function hasFunction(obj, param) {
    return (typeof obj[param] === 'function');
}
o = {
    foo: function () {}
}
hasFunction(o, 'foo'); //true
hasFunction(o, 'bar'); //false
于 2012-06-21T18:40:04.587 に答える
1

これは今日ではあまり役に立ちませんが(ブラウザのサポートが不十分なため)、Proxy APIを使用すると、オブジェクトへのプロパティアクセスをインターセプトするコードを記述できます。言い換えれば、あなたが書くとき:

obj.foo();

プロキシのトラップは、プロパティが元のオブジェクトに実際に存在するかどうかに関係なく、必要なもの(呼び出される)を返すことができます。

于 2012-06-21T19:21:22.980 に答える