Это 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, если вы этого не сделаете придется, если вы не нормализуете новые методы в устаревших браузерах.
К счастью, вы всегда можете просто предварительно сопоставить типы или имена конструкторов с методами (остерегайтесь IE <= 8, который не имеет <object> .constructor.name, требующего, чтобы вы анализировали его из результатов toString из свойства конструктора). Вы по-прежнему проверяете имя конструктора (typeof является бесполезным в JS при сравнении объектов), но, по крайней мере, он читается намного лучше, чем гигантский оператор 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 для этого. Я уверен, что есть опечатки / ошибки.