Я понимаю, что Javascript не имеет классов и не имеет классического наследования ООП. Но я нахожу такие шаблоны настолько полезными, что я хотел создать простой способ для моделирования такого поведения, в идеале, используя при этом лучшие стороны гибкости Javascript. Каковы плюсы и минусы следующего подхода?
В моей пользовательской библиотеке есть следующие функции:
function inherit(superClass, args, instance) {
var subClass = inherit.caller;
var o = new superClass(args);
for(p in o) {
if(o.hasOwnProperty(p)) init(instance, p, o[p]);
else init(subClass.prototype, p, o[p]);
}
}
function isUndefined(x) {var u; return x === u;}
// sets p to value only if o[p] is undefined
function init(o, p, value) {if(isUndefined(o[p])) o[p] = value;}
Эта настройка требует двух соглашений:
- Функции, которые моделируют классы, должны принимать один аргумент: объект с именованными свойствами
- Функции, желающие «наследовать» от другого, должны вызывать функцию наследования.
Вот пример того, что вы получаете в результате (вставьте в командную строку Firebug вместе с функциями библиотеки, чтобы увидеть его в действии):
function SuperClass(args) {
this.x = args.x;
}
SuperClass.prototype.p = 'SuperClass prototype property p';
function SubClass(args) {
inherit(SuperClass, args, this);
this.y = args.y;
}
SubClass.prototype.q = 'SubClass prototype property q';
var o = new SubClass({
x: 'x set in SuperClass',
y: 'y set in SubClass'
});
console.dir(o); // correctly has properties x, y, p, and q
['x', 'y', 'p', 'q'].forEach(function(prop) {
// true for x and y, false for p and q
console.log("o.hasOwnProperty('" + prop + "')", o.hasOwnProperty(prop));
});
console.log("o instanceof SubClass: ", o instanceof SubClass); // true
console.log("o instanceof SuperClass: ", o instanceof SuperClass); // false
Мне известны следующие минусы:
- Изменение прототипа суперкласса не повлияет на ваш экземпляр объекта, как вы могли ожидать от наследования в стиле прототипа
- Объект экземпляра не будет зарегистрирован как экземпляр суперкласса (хотя он все равно будет крякать как один)
- Соглашения об аргументах могут раздражать
и плюсы:
- Требуется только один вызов функции (легко реализовать)
- Различает свойства прототипа и свойства экземпляра
- Аргументы, передаваемые подклассу, также передаются суперклассу
- Свойства экземпляра, установленные конструктором суперкласса, сразу же доступны в конструкторе подкласса
- Многократное наследование легко, просто вызовите многократное наследование в вашем подклассе
- Не перезаписывает существующие свойства подкласса
Плюсы 3 - 6 специально делают этот метод более полезным для меня, чем метод SubClass.prototype = new SuperClass()
. Другие методы, такие как моделирование классов додзё, намного сложнее, я думаю, что это излишне.
Итак, скажите мне, что вы думаете. И если кто-то еще делал это раньше, пожалуйста, дайте мне знать, я не собирался дублировать какие-либо идеи.