Я родом из классов объектно-ориентированных языков, и в последнее время я изучаю эти модные динамические языки (JavaScript, Python и Lua), и мне нужны несколько советов о том, как использовать объектно-ориентированный объект на этих языках. Было бы полезно знать подводные камни и недостатки такого подхода и преимущества по сравнению с традиционным ОО.
Общее представление, которое я получил, состоит в том, что объектно-ориентированное программирование на основе прототипов в основном является программированием с объектами, но не имеет стандарта на то, как их использовать, тогда как в обычном объектно-ориентированном проектировании существует фиксированный предопределенный способ создания и использования объектов.
В общем, каковы хорошие, плохие и уродливые стороны такого подхода?
Я бы предположил: прототип OO - Javascript, традиционный OO - большинство других языков OO. Я бы посчитал Python традиционным объектно-ориентированным языком (хотя вы, вероятно, можете заставить его действовать как прототип языка объектно-ориентированного программирования, если хотите).
@Dan: Интересное предположение - тот факт, что это неочевидно, означает, что спрашивающий должен предоставить определения или примеры. В противном случае вопрос будет слишком расплывчатым, чтобы ответить.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Хорошо, во-первых, модель-прототип в действительности не так уж и отличается; Smalltalk использует похожую схему; класс - это объект с методами класса.
С точки зрения класса POV, класс на самом деле является классом эквивалентности объектов с одинаковыми данными и всеми одинаковыми методами; вы можете рассматривать добавление метода к прототипу как создание нового подкласса.
Реализация проста, но очень затрудняет эффективную проверку типов.
Чтобы сохранить полосу пропускания, вот ссылка на мой ответ на тему «Как я могу эмулировать« классы »в JavaScript? (со сторонней библиотекой или без нее)». Он содержит дополнительные ссылки, а также примеры.
Краткий ответ: сердце прототипа OO JavaScript - это делегирование. В этом стиле ООП разные объекты одного и того же «класса» могут делегировать обработку методов и свойств одному и тому же прототипу (обычно какому-то третьему объекту):
var foo = {
property: 42,
inc: function(){
++this.counter;
},
dec: function(){
--this.counter;
}
};
// Note: foo does not define `counter`.
Давайте создадим конструктор для объектов с foo в качестве прототипа. Фактически, все необработанное будет делегировано foo.
var Bar = function(){
this.counter = 0;
};
Bar.prototype = foo; // This is how we set up the delegation.
// Some people refer to Bar (a constructor function) as "class".
var bar = new Bar();
console.info(bar.counter); // 0 --- Comes from bar itself
console.info(bar.property); // 42 --- Not defined in bar, comes from foo
bar.inc(); // Not defined in bar => delegated to foo
bar.inc();
bar.dec(); // Not defined in bar => delegated to foo
// Note: foo.inc() and foo.dec() are called but this === bar
// that is why bar is modified, not foo.
console.info(bar.counter); // 1 --- Comes from bar itself
Определим inc() прямо на баре:
bar.inc = function(){
this.counter = 42;
};
bar.inc(); // Defined in bar => calling it directly.
// foo.inc() is not even called.
console.info(bar.counter); // 42 --- Comes from bar
Настройка единой цепочки наследования:
var Baz = function(){
this.counter = 99;
};
Baz.protype = new Bar();
var baz = new Baz();
console.info(baz.counter); // 99
baz.inc();
console.info(baz.counter); // 100
console.info(baz instanceof Baz); // true
console.info(baz instanceof Bar); // true
console.info(baz instanceof Object); // true
Аккуратно, а?
console.info (bar.prototype); Разве это не должно быть: bar.property?
Объектно-ориентированный объект на основе прототипов плохо поддается проверке статического типа, что некоторые могут счесть плохой или уродливой вещью. Основанные на прототипах OO делает имеют стандартный способ создания новых объектов, вы клонировать и изменять существующие объекты. Вы также можете строить фабрики и т. д.
Я думаю, что людям больше всего нравится («хорошо») то, что объектно-ориентированный объект на основе прототипов очень похож на легкий и гибкий, предлагая очень высокая удельная мощность.
Для советы по использованию объектно-ориентированного проектирования на основе прототипов отличным местом для начала является исходная статья Self о Сила простоты.
Прежде чем беспокоиться о том, как имитировать наследование на основе классов в JavaScript, ознакомьтесь с Прототипное наследование в JavaScript.
Классическое наследование по своей сути ошибочно с точки зрения гибкости, поскольку мы говорим, что «этот объект относится к этому типу, а не к другому». Некоторые языки вводят множественное наследование, чтобы облегчить это, но множественное наследование имеет свои недостатки, и поэтому преимущества чистой композиции перед наследованием (которое в статически типизированном языке является средой выполнения, а не механизмом времени компиляции) становятся очевидными.
Подняв концепцию композиции на этот «чистый» уровень, мы можем полностью исключить классическое наследование вместе со статической типизацией. Составляя объекты во время выполнения и используя их в качестве схем (прототипный подход), нам никогда не нужно беспокоиться о слишком тесной упаковке объектов посредством наследования или обременять себя проблемами, присущими подходам с множественным наследованием.
Таким образом, прототипирование означает более гибкую разработку модулей.
Конечно, совсем другое дело сказать, что разрабатывать ЛЕГКО без статической типизации. ИМО, это не так.
"классы объектно-ориентированных языков" - не могли бы вы привести пример языка или двух? «традиционный объектно-ориентированный подход» - можете ли вы привести два примера языка?