Классическое наследование против protoypal наследования в javascript

У меня есть множество ссылок и не может получить хорошее представление о различии между классическим наследованием и прототипным наследованием?

Я узнал кое-что из них, но я все еще смущен понятиями.

Классическое наследование

// Shape - superclass
function Shape() {
  this.x = 0;
  this.y = 0;
}

//superclass method
Shape.prototype.move = function(x, y) {
    this.x += x;
    this.y += y;
    console.info("Shape moved.");
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); //call super constructor.
}

//subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);

Использует ли классическое наследование прототипное наследование внутри?

http://aaditmshah.github.io/why-prototypal-inheritance-matters/

Из вышеприведенной ссылки я узнал, что мы не можем добавлять новые методы во время выполнения в классическом наследовании. Это верно? Но вы можете проверить приведенный выше код Я могу добавить метод "move" и любые методы во время выполнения через прототип. Итак, это прототип, основанный на классическом наследовании? Если да, то каково фактическое классическое наследование и наследование прототипа? Я смущен этим.

Прототипное наследование.

function Circle(radius) {
    this.radius = radius;
}
Circle.prototype.area = function () {
    var radius = this.radius;
    return Math.PI * radius * radius;
};
Circle.prototype.circumference: function () {
    return 2 * Math.PI * this.radius;
};
var circle = new Circle(5);
var circle2 = new Circle(10);

Это похоже на классическое наследование? Я полностью смущен тем, что такое прототипное наследование? Что такое классическое наследование? Почему классическое наследование плохое?

Можете ли вы дать мне простой пример для лучшего понимания этого простым способом.

Спасибо,

Шив

Ответ 1

Оба образца кода, которые вы продемонстрировали в своем вопросе, используют прототипное наследование. На самом деле любой объектно-ориентированный код, который вы пишете в JavaScript, является парадигмой прототипного наследования. JavaScript просто не имеет классического наследования. Это должно немного прояснить ситуацию:

                                   Inheritance
                                        |
                         +-----------------------------+
                         |                             |
                         v                             v
                    Prototypal                     Classical
                         |
         +------------------------------+
         |                              |
         v                              v
Prototypal Pattern             Constructor Pattern

Как вы можете видеть, прототипное наследование и классическое наследование - это две разные парадигмы наследования. Некоторые языки, такие как Self, Lua и JavaScript, поддерживают прототипное наследование. Однако большинство языков, таких как С++, Java и С#, поддерживают классическое наследование.


Краткий обзор объектно-ориентированного программирования

Оба прототипального наследования и классического наследования являются объектно-ориентированными парадигмами программирования (т.е. они имеют дело с объектами). Объекты - это просто абстракции, которые инкапсулируют свойства объекта реального мира (т.е. Представляют собой реальные слова в программе). Это называется абстракцией.

Абстракция: Представление реальных вещей в компьютерных программах.

Теоретически абстракция определяется как "общая концепция, сформированная путем извлечения общих черт из конкретных примеров". Однако ради этого объяснения мы будем использовать вышеупомянутое определение.

Теперь некоторые объекты имеют много общего. Например, грязевой велосипед и Harley Davidson имеют много общего.

Велосипед грязи:

A mud bike.

Харли Дэвидсон:

A Harley Davidson

Бродяга и Харли Дэвидсон - оба байка. Следовательно, велосипед - это обобщение как мотоцикла грязи, так и Harley Davidson.

                   Bike
                     |
    +---------------------------------+
    |                                 |
    v                                 v
Mud Bike                       Harley Davidson

В приведенном выше примере велосипед, грязевой велосипед и Harley Davidson - все абстракции. Однако велосипед - это более общая абстракция байдажа грязи и Harley Davidson (т.е. И грязевой велосипед, и Harley Davidson являются определенными типами велосипедов).

Обобщение: Абстракция более конкретной абстракции.

В объектно-ориентированном программировании мы создаем объекты (которые являются абстракциями объектов реального мира), и мы используем либо классы, либо прототипы для создания обобщений этих объектов. Обобщения создаются посредством наследования. Велосипед - это обобщение грязевого байка. Следовательно, грязевые велосипеды наследуются от велосипедов.


Классическое объектно-ориентированное программирование

В классическом объектно-ориентированном программировании мы имеем два типа абстракций: классы и объекты. Объект, как упоминалось ранее, является абстракцией объекта реального мира. Класс, с другой стороны, представляет собой абстракцию объекта или другого класса (т.е. Это обобщение). Например, рассмотрим:

+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity |                Comments               |
+----------------------+----------------+---------------------------------------+
| 0                    | John Doe       | Real World Entity.                    |
| 1                    | johnDoe        | Variable holding object.              |
| 2                    | Man            | Class of object johnDoe.              |
| 3                    | Human          | Superclass of class Man.              |
+----------------------+----------------+---------------------------------------+

Как вы можете видеть в классических объектно-ориентированных языках программирования, объекты - это только абстракции (т.е. все объекты имеют уровень абстракции 1), а классы - это только обобщения (т.е. все классы имеют уровень абстракции больше 1).

Объекты в классических объектно-ориентированных языках программирования могут быть созданы только посредством экземпляров классов:

class Human {
    // ...
}

class Man extends Human {
    // ...
}

Man johnDoe = new Man();

В суммировании в классических объектно-ориентированных языках программирования объекты представляют собой абстракции объектов реального мира, а классы - обобщения (т.е. абстракции любых объектов или других классов).

Следовательно, по мере того как уровень абстракции увеличивается, сущности становятся более общими, и по мере уменьшения уровня абстракции сущности становятся более конкретными. В этом смысле уровень абстракции аналогичен шкале от более конкретных объектов до более общих объектов.


Прототипное объектно-ориентированное программирование

Прототипные объектно-ориентированные языки программирования намного проще, чем классические объектно-ориентированные языки программирования, потому что в прототипном объектно-ориентированном программировании мы имеем только один тип абстракции (т.е. объекты). Например, рассмотрим:

+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity |                Comments               |
+----------------------+----------------+---------------------------------------+
| 0                    | John Doe       | Real World Entity.                    |
| 1                    | johnDoe        | Variable holding object.              |
| 2                    | man            | Prototype of object johnDoe.          |
| 3                    | human          | Prototype of object man.              |
+----------------------+----------------+---------------------------------------+

Как вы можете видеть в прототипальных объектно-ориентированных языках программирования, объекты представляют собой абстракции любых объектов реального мира (в этом случае они просто называются объектами) или других объектов (в этом случае они называются прототипами тех объектов, которые они абстрактны), Следовательно, прототип является обобщением.

Объекты в прототипальных объектно-ориентированных языках программирования могут быть созданы либо ex-nihilo (т.е. из ничего), либо из другого объекта (который становится прототипом вновь созданного объекта):

var human = {};
var man = Object.create(human);
var johnDoe = Object.create(man);

По моему скромному мнению прототипные объектно-ориентированные языки программирования более мощные, чем классические языки объектно-ориентированного программирования, потому что:

  • Существует только один тип абстракции.
  • Обобщения - это просто объекты.

К настоящему времени вы, должно быть, осознали разницу между классическим наследованием и прототипным наследованием. Классическое наследование ограничено классами, наследуемыми от других классов. Однако прототипное наследование включает в себя не только прототипы, наследуемые от других прототипов, но и объекты, наследуемые от прототипов.


Изоморфизм прототипа класса

Вы, должно быть, заметили, что прототипы и классы очень похожи. Это правда. Они есть. На самом деле они настолько похожи, что вы действительно можете использовать прототипы для моделирования классов:

function CLASS(base, body) {
    if (arguments.length < 2) body = base, base = Object.prototype;
    var prototype = Object.create(base, {new: {value: create}});
    return body.call(prototype, base), prototype;

    function create() {
        var self = Object.create(prototype);
        return prototype.hasOwnProperty("constructor") &&
            prototype.constructor.apply(self, arguments), self;
    }
}

Используя вышеуказанную функцию CLASS, вы можете создавать прототипы, которые выглядят как классы:

var Human = CLASS(function () {
    var milliseconds = 1
      , seconds      = 1000 * milliseconds
      , minutes      = 60 * seconds
      , hours        = 60 * minutes
      , days         = 24 * hours
      , years        = 365.2425 * days;

    this.constructor = function (name, sex, dob) {
        this.name = name;
        this.sex = sex;
        this.dob = dob;
    };

    this.age = function () {
        return Math.floor((new Date - this.dob) / years);
    };
});

var Man = CLASS(Human, function (Human) {
    this.constructor = function (name, dob) {
        Human.constructor.call(this, name, "male", dob);
        if (this.age() < 18) throw new Error(name + " is a boy, not a man!");
    };
});

var johnDoe = Man.new("John Doe", new Date(1970, 0, 1));

Обратное неверно (т.е. вы не можете использовать классы для моделирования прототипов). Это связано с тем, что прототипы являются объектами, но классы не являются объектами. Это совершенно другой тип абстракции.


Заключение

В суммировании мы узнали, что абстракция является "общей концепцией, сформированной путем извлечения общих черт из конкретных примеров" и что обобщение является "абстракцией более конкретной абстракции". Мы также узнали о различиях между прототипным и классическим наследованием и о том, как обе они являются двумя гранями одной и той же монеты.

На прощальной заметке я хотел бы отметить, что существуют два шаблона прототипального наследования: прототипный шаблон и шаблон конструктора. Прототипная модель представляет собой канонический образец прототипного наследования, тогда как шаблон конструктора используется для того, чтобы сделать прототипное наследование более похожим на классическое наследование. Лично я предпочитаю прототипную схему.

P.S. Я тот парень, который написал сообщение в блоге " Почему вопрос о прототипном наследовании" и ответил на вопрос "Преимущества прототипного наследования по классическому?". Мой ответ - принятый ответ.

Ответ 2

Самое замечательное в JavaScript - это способность избавиться от жестких правил классического наследования и позволить объектам наследовать свойства от других объектов.

Классическое наследование. Функция-конструктор создает экземпляр с помощью ключевого слова "новое". Этот новый экземпляр наследует свойства родительского класса.

Прототипное наследование. Экземпляр создается путем клонирования существующего объекта, который служит прототипом. Этот экземпляр, часто создаваемый с использованием функции factory или "Object.create()", может воспользоваться выборочным наследованием от множества разных объектов.

Ответ 3

Прежде чем перейти к наследованию, мы рассмотрим две первичные модели для создания экземпляров (объектов) в javascript:

Классическая модель: Объект создается из плана (класса)

class Person {
  fn() {...}
} // or constructor function say, function Person() {}

// create instance
let person = new Person();

Прототипная модель: Объект создается непосредственно из другого объекта.

// base object
let Person = { fn(){...} }

// instance
let person = Object.create(Person);

В любом случае Inheritance * достигается путем связывания объектов с использованием прототипа.

(* методы базового класса доступны через производный класс через объект-прототип и не должны явно присутствовать в производном классе.)

Вот хорошее объяснение, чтобы лучше понять (http://www.objectplayground.com/)