これはJavaScriptです。うまくいけば、このようなジレンマを否定するのに役立つ中道があることがわかります。また、サポートされていない「タイプ」が何かに引っかかっているか、誰かがそれを使用しようとしたときに壊れるかどうかは、コンパイル対ランタイムがないため、実際には関係ありません。間違って使用すると壊れます。破損したことを隠そうとしても、破損したときに途中で動作させようとしても、何かが破損しているという事実は変わりません。
だからあなたのケーキを食べて、それを食べて、名前を付けて、すべての正しい場所にすべての正しい詳細を含めて、すべてを本当に、本当に明白にすることによって、タイプの混乱と不必要な破損を避けることを学んでください。
まず、型を確認する前に、アヒルを一列に並べる習慣を身につけることを強くお勧めします。もっとも効率的で効率的な(ただし、ネイティブコンストラクターが常に最適とは限りません)ことは、最初にプロトタイプをヒットすることです。そうすれば、メソッドはサポートされている型が何であるかを気にする必要さえありません。
String.prototype.pullRabbit = function(){
//do something string-relevant
}
HTMLElement.prototype.pullRabbit = function(){
//do something HTMLElement-relevant
}
Magician.pullRabbitFrom = function(someThingy){
return someThingy.pullRabbit();
}
注:すべてがObjectから継承されるため、Objectに対してこれを行うのは悪い形式と広く見なされています。私も個人的には機能を避けています。一部の人はネイティブコンストラクターのプロトタイプに触れることに不安を感じるかもしれませんが、これは悪いポリシーではないかもしれませんが、この例は独自のオブジェクトコンストラクターで作業する場合に役立ちます。
それほど複雑ではないアプリで別のライブラリから何かを壊すような特定の用途のメソッドについては、このアプローチについては心配しませんが、JavaScriptのネイティブメソッド全体で過度に一般的なものをアサートしないようにするのは良い本能です古いブラウザで新しいメソッドを正規化する場合を除きます。
幸いなことに、メソッドまたはコンストラクター名をメソッドにいつでも事前マップできます(<object> .constructor.nameを持たないIE <= 8に注意してください。コンストラクタープロパティのtoString結果から解析する必要があります)。あなたはまだコンストラクタ名をチェックしています(オブジェクトを比較するときにJSではtypeofは一種の役に立たない)が、少なくともそれは巨大なswitchステートメントまたはメソッドのすべての呼び出しでif / elseチェーンよりもはるかに優れているさまざまなオブジェクト。
var rabbitPullMap = {
String: ( function pullRabbitFromString(){
//do stuff here
} ),
//parens so we can assign named functions if we want for helpful debug
//yes, I've been inconsistent. It's just a nice unrelated trick
//when you want a named inline function assignment
HTMLElement: ( function pullRabitFromHTMLElement(){
//do stuff here
} )
}
Magician.pullRabbitFrom = function(someThingy){
return rabbitPullMap[someThingy.constructor.name]();
}
または、同じマップアプローチを使用して、異なるオブジェクトタイプの「this」コンポーネントにアクセスして、継承されたプロトタイプに触れずにメソッドであるかのように使用したい場合:
var rabbitPullMap = {
String: ( function(obj){
//yes the anon wrapping funcs would make more sense in one spot elsewhere.
return ( function pullRabbitFromString(obj){
var rabbitReach = this.match(/rabbit/g);
return rabbitReach.length;
} ).call(obj);
} ),
HTMLElement: ( function(obj){
return ( function pullRabitFromHTMLElement(obj){
return this.querySelectorAll('.rabbit').length;
} ).call(obj);
} )
}
Magician.pullRabbitFrom = function(someThingy){
var
constructorName = someThingy.constructor.name,
rabbitCnt = rabbitPullMap[constructorName](someThingy);
console.log(
[
'The magician pulls ' + rabbitCnt,
rabbitCnt === 1 ? 'rabbit' : 'rabbits',
'out of her ' + constructorName + '.',
rabbitCnt === 0 ? 'Boo!' : 'Yay!'
].join(' ');
);
}
すべての言語IMOの一般的な原則として、実際にトリガーをプルするコードに到達する前に、このような分岐の詳細を整理することをお勧めします。そうすれば、そのトップAPIレベルに関係するすべてのプレーヤーを簡単に確認できますが、誰かが気にする詳細がどこにあるのかを簡単に整理することもできます。
注:RLを実際に使用している人はいないと想定しているため、これはすべてテストされていません。タイプミス/バグがあると確信しています。