Este é o JavaScript. À medida que você melhora, descobre que muitas vezes há um caminho intermediário que ajuda a negar dilemas como esse. Além disso, realmente não importa se um 'tipo' não suportado é capturado por algo ou se quebra quando alguém tenta usá-lo, porque não há compilação versus tempo de execução. Se você usar errado, ele quebra. Tentar esconder que ele quebrou ou fazê-lo funcionar a meio caminho quando quebrou não muda o fato de que algo está quebrado.
Portanto, coma seu bolo e coma-o também, e aprenda a evitar confusão de tipo e quebra desnecessária, mantendo tudo muito, muito óbvio, como bem nomeado e com todos os detalhes certos, nos lugares certos.
Primeiro de tudo, eu recomendo que você tenha o hábito de colocar seus patos em uma fila antes de precisar verificar os tipos. A coisa mais enxuta e eficiente (mas nem sempre melhor no que diz respeito aos construtores nativos) seria acertar os protótipos primeiro, para que seu método nem precise se preocupar com o tipo suportado em jogo.
String.prototype.pullRabbit = function(){
//do something string-relevant
}
HTMLElement.prototype.pullRabbit = function(){
//do something HTMLElement-relevant
}
Magician.pullRabbitFrom = function(someThingy){
return someThingy.pullRabbit();
}
Nota: É amplamente considerado como uma forma incorreta fazer isso com o Object, pois tudo herda do Object. Eu pessoalmente evitaria a função também. Alguns podem se sentir impacientes ao tocar no protótipo de qualquer construtor nativo, o que pode não ser uma política ruim, mas o exemplo ainda pode servir ao trabalhar com seus próprios construtores de objetos.
Eu não me preocuparia com essa abordagem para um método de uso específico que provavelmente não perturba algo de outra biblioteca em um aplicativo menos complicado, mas é um bom instinto evitar evitar algo excessivamente geral nos métodos nativos em JavaScript, se você não o fizer. a menos que você esteja normalizando métodos mais recentes em navegadores desatualizados.
Felizmente, você sempre pode pré-mapear tipos ou nomes de construtores para métodos (cuidado com o IE <= 8, que não possui <object> .constructor.name, exigindo que você os analise dos resultados de toString da propriedade construtor). Você ainda está checando o nome do construtor (typeof é meio inútil em JS ao comparar objetos), mas pelo menos parece muito melhor do que uma declaração de switch gigante ou encadeia se / else em todas as chamadas do método para o que poderia ser amplo variedade de objetos.
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]();
}
Ou usando a mesma abordagem de mapa, se você quiser acessar o componente 'this' dos diferentes tipos de objetos para usá-los como se fossem métodos sem tocar em seus protótipos herdados:
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(' ');
);
}
Um bom princípio geral em qualquer idioma da IMO é tentar resolver detalhes de ramificação como este antes de chegar ao código que realmente aciona o gatilho. Dessa forma, é fácil ver todos os jogadores envolvidos no nível superior da API para obter uma boa visão geral, mas também é muito mais fácil descobrir onde os detalhes com os quais alguém pode se importar provavelmente serão encontrados.
Nota: tudo isso não foi testado, porque presumo que ninguém realmente tenha um uso de RL para isso. Tenho certeza de que há erros de digitação / erros.