Нет понятия "этот класс должен иметь эти функции" (то есть интерфейсов как таковых), потому что:
- Наследование JavaScript основано на объектах, а не на классах. Это не имеет большого значения, пока вы не поймете:
- JavaScript - это чрезвычайно динамически типизированный язык - вы можете создать объект с надлежащими методами, которые бы привели его в соответствие с интерфейсом, , а затем отменить определение всего, что привело его . Было бы так легко подорвать систему типов - даже случайно! - что не стоит пытаться создать систему типов.
Вместо этого в JavaScript используется то, что называется duck typing . (Если он ходит как утка и крякает как утка, то, что касается JS, это утка.) Если ваш объект имеет методы quack (), walk () и fly (), код может использовать его везде, где он ожидает объект, который может ходить, крякать и летать, не требуя реализации какого-либо "Duckable" интерфейса. Интерфейс - это в точности набор функций, которые использует код (и возвращаемые значения из этих функций), и с помощью утки вы получаете это бесплатно.
Это не значит, что ваш код не потерпит неудачу на полпути, если вы попытаетесь вызвать some_dog.quack()
; вы получите TypeError. Честно говоря, если вы говорите собакам крякать, у вас есть немного большие проблемы; Печатание утки работает лучше всего, когда вы, так сказать, держите всех своих уток в ряд и не позволяете собакам и уткам смешиваться, если вы не относитесь к ним как к обычным животным. Другими словами, даже если интерфейс плавный, он все еще там; часто бывает ошибкой передавать собаку в код, который ожидает, что она сначала будет крякать и летать.
Но если вы уверены, что поступаете правильно, вы можете обойти проблему собаки-кряка, проверив наличие определенного метода, прежде чем пытаться его использовать. Что-то вроде
if (typeof(someObject.quack) == "function")
{
// This thing can quack
}
Таким образом, вы можете проверить все методы, которые вы можете использовать, прежде чем использовать их. Синтаксис довольно уродливый, хотя. Есть немного более красивый способ:
Object.prototype.can = function(methodName)
{
return ((typeof this[methodName]) == "function");
};
if (someObject.can("quack"))
{
someObject.quack();
}
Это стандартный JavaScript, поэтому он должен работать в любом интерпретаторе JS, который стоит использовать. Это имеет дополнительное преимущество чтения как английский.
Для современных браузеров (то есть практически для любого браузера, кроме IE 6-8), есть даже способ не отображать свойство в for...in
:
Object.defineProperty(Object.prototype, 'can', {
enumerable: false,
value: function(method) {
return (typeof this[method] === 'function');
}
}
Проблема в том, что у объектов IE7 вообще нет .defineProperty
, а в IE8 он предположительно работает только с хост-объектами (то есть с элементами DOM и т. Д.). Если проблема совместимости, вы не можете использовать .defineProperty
. (Я даже не буду упоминать IE6, потому что он больше не имеет значения за пределами Китая.)
Другая проблема заключается в том, что некоторые стили кодирования любят предполагать, что все пишут плохой код, и запрещают изменять Object.prototype
в случае, если кто-то хочет слепо использовать for...in
. Если вы заботитесь об этом или используете код (IMO broken ), который это делает, попробуйте немного другую версию:
function can(obj, methodName)
{
return ((typeof obj[methodName]) == "function");
}
if (can(someObject, "quack"))
{
someObject.quack();
}