Це 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 при порівнянні об'єктів), але принаймні він читає набагато приємніше, ніж гігантський вимикач переключення або 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]();
}
Або використовуючи той самий підхід до карти, якщо ви хочете отримати доступ до компонента "цей" різних типів об'єктів, щоб використовувати їх так, ніби вони були методами, не торкаючись їх успадкованих прототипів:
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 для цього. Я впевнений, що є помилки друку / помилки.