Dies ist JavaScript. Wenn Sie es besser machen, werden Sie feststellen, dass es oft einen Mittelweg gibt, der hilft, solche Dilemmata zu überwinden. Außerdem spielt es keine Rolle, ob ein nicht unterstützter 'Typ' von etwas abgefangen wird oder abbricht, wenn jemand versucht, ihn zu verwenden, weil es keine Kompilierung oder Laufzeit gibt. Wenn Sie es falsch verwenden, bricht es. Der Versuch zu verbergen, dass es kaputt gegangen ist oder auf halbem Weg funktioniert, wenn es kaputt gegangen ist, ändert nichts an der Tatsache, dass etwas kaputt gegangen ist.
Nehmen Sie also Ihren Kuchen mit und essen Sie ihn auch und lernen Sie, Typverwechslungen und unnötige Brüche zu vermeiden, indem Sie alles wirklich, wirklich offensichtlich und mit den richtigen Details an den richtigen Stellen aufbewahren.
Zuallererst ermutige ich Sie sehr, sich daran zu gewöhnen, Ihre Enten hintereinander zu bringen, bevor Sie die Typen überprüfen müssen. Am schlanksten und effizientesten (aber nicht immer am besten, wenn es um native Konstruktoren geht) ist es, zuerst die Prototypen zu testen, damit sich Ihre Methode nicht einmal darum kümmern muss, welcher unterstützte Typ im Spiel ist.
String.prototype.pullRabbit = function(){
//do something string-relevant
}
HTMLElement.prototype.pullRabbit = function(){
//do something HTMLElement-relevant
}
Magician.pullRabbitFrom = function(someThingy){
return someThingy.pullRabbit();
}
Hinweis: Es wird allgemein als schlechte Form angesehen, dies mit Object zu tun, da alles von Object erbt. Ich persönlich würde die Funktion auch meiden. Einige fühlen sich vielleicht ärgerlich, wenn sie den Prototyp eines nativen Konstruktors anfassen, was vielleicht keine schlechte Richtlinie ist, aber das Beispiel kann trotzdem bei der Arbeit mit Ihren eigenen Objektkonstruktoren hilfreich sein.
Ich würde mir keine Sorgen um diesen Ansatz für eine Methode machen, die für eine bestimmte Verwendung geeignet ist und in einer weniger komplizierten App wahrscheinlich nichts aus einer anderen Bibliothek herausholt, aber es ist ein guter Instinkt, zu vermeiden, dass bei systemeigenen Methoden in JavaScript etwas zu allgemein behauptet wird, wenn dies nicht der Fall ist müssen, es sei denn, Sie normalisieren neuere Methoden in veralteten Browsern.
Glücklicherweise können Sie Typen oder Konstruktornamen immer nur vorab auf Methoden abbilden (achten Sie darauf, dass IE <= 8 nicht <object> .constructor.name enthält, sodass Sie es aus den toString-Ergebnissen der Konstruktoreigenschaft analysieren müssen). Sie überprüfen immer noch den Konstruktornamen (typeof ist in JS beim Vergleichen von Objekten irgendwie nutzlos), aber es liest sich zumindest viel besser als eine riesige switch-Anweisung oder if / else-Kette in jedem Aufruf der Methode, die eine breite sein könnte Vielzahl von Objekten.
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]();
}
Oder verwenden Sie denselben Kartenansatz, wenn Sie möchten, dass Sie auf die 'this'-Komponente der verschiedenen Objekttypen zugreifen können, um sie so zu verwenden, als wären sie Methoden, ohne ihre vererbten Prototypen zu berühren:
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(' ');
);
}
Ein gutes allgemeines Prinzip in jeder Sprache IMO ist, zu versuchen, Verzweigungsdetails wie diese zu sortieren, bevor Sie zu Code gelangen, der tatsächlich den Auslöser drückt. Auf diese Weise ist es einfach, alle beteiligten Spieler auf dieser obersten API-Ebene zu sehen, um einen guten Überblick zu erhalten, aber es ist auch viel einfacher herauszufinden, wo die Details zu finden sind, die jemanden interessieren könnten.
Hinweis: Dies ist alles ungetestet, da ich annehme, dass niemand eine RL-Verwendung dafür hat. Ich bin mir sicher, dass es Tippfehler gibt.