Как использовать Object.create для наследования внутри модулей в node.js

#node.js #inheritance #prototypal-inheritance #object-create

#node.js #наследование #прототипное наследование #объект-создать

Вопрос:

У меня есть модуль Vehicle, который содержит общую информацию о транспортном средстве. У меня есть другой модуль Car, который добавляет больше функциональности объекту Vehicle.

 // Pseudo code only. The final functions do not have to resemble this
var vehicle = require('vehicle')
vehicle.terrain = 'Land'
var car = vehicle.createCar()
// car and anotherCar will have unique Car-related values,
// but will use the same Vehicle info
var anotherCar = vehicle.createCar()
  

Я рассматриваю возможность использования Object.create для модуля Car, но не уверен, куда должны направляться вызовы Object.create.

  • Должен ли у меня быть конструктор в модуле Car, который берет экземпляр объекта Vehicle и выполняет Object.create с экземпляром Vehicle в качестве прототипа?
  • Или Object.create должен выполняться в функции объекта Vehicle, например createCar? Моя проблема с этим способом заключается в том, что Car должен заботиться о том, чтобы он был производным от Vehicle, Vehicle не должен знать, что Car требует этого.
  • Или даже если Object.create — правильный подход.

Пожалуйста, любые примеры и лучшие практики были бы высоко оценены.

Обновить:

Я изменил пример, чтобы лучше отразить проблему наследования, которую я пытаюсь решить.

Ответ №1:

имо, я думаю, вы описываете шаблон builder, а не наследование — я бы не стал использовать object.create для этого. VehicleBuilder отвечает за создание объекта, который имеет определенные свойства, связанные с ним.

 var builder = new VehicleBuilder();
builder.terrain = 'Land';
builder.wheelCount = 2;
builder.color = "blue";
var motorcycle = builder.createVehicle();
  

Это может использовать что-то вроде:

 VehicleBuilder.prototype.createVehicle = function(){
    var me = this;
    return new Vehicle({
         color: me.color,
         terrain: me.terrain,
         wheelCount: me.wheelCount
    });
}
  

Если вы посмотрите на типичный шаблон наследования в js, это нечто гораздо более четко определенное и использующее два основных шаблона в node. Один из них — util.inherits. Его код прост:https://github.com/joyent/node/blob/master/lib/util.js#L423-428

 exports.inherits = function(ctor, superCtor) {
  ctor.super_ = superCtor;
  ctor.prototype = Object.create(superCtor.prototype, {
    constructor: { value: ctor, enumerable: false }
  });
};
  

И второй — это вызов родительского конструктора в конструкторе дочернего класса.

 function ChildClass(){
    SuperClass.call(this); // here
}
  

Пример: https://github.com/joyent/node/blob/master/lib/stream.js#L25-28

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

Комментарии:

1. Спасибо за примеры. В итоге я выбрал util.inherits, но мне понравилась идея конструктора.

Ответ №2:

Я бы порекомендовал другой подход

 // foo.js
var topic = require("topic");
topic.name = "History";
topic.emit("message");
topic.on("message", function() { /* ... */ });

// topic.js
var events = require("events");
var Topic = function() {

};

// inherit from eventEmitter
Topic.prototype = new events.EventEmitter();
exports.module = new Topic;
  

У вас есть хороший EventEmitter способ сделать передачу сообщений за вас. Я рекомендую вам просто расширить прототип Topic с его помощью.

Комментарии:

1. Я изменил свой пример, чтобы лучше отразить базовое наследование, которого я пытаюсь достичь, и как использовать Object.create для этого. Исходный пример темы / публикации / подписки был слишком запутанным с концепцией узла о передаче событий.

Ответ №3:

Почему бы просто не использовать наследование на основе собственного прототипа js? Предоставьте свой конструктор напрямую, используя module.exports:

 //vehicle.js
module.exports = function() {
  //make this a vehicle somehow
}
  

Затем:

 // Pseudo code only. The final functions do not have to resemble this
var Vehicle = require('vehicle')
Vehicle.terrain = 'Land'
var car = new Vehicle()
// car and anotherCar will have unique Car-related values,
// but will use the same Vehicle info
var anotherCar = new Vehicle()
  

Комментарии:

1. Нет. Вы только что превратили все транспортные средства в наземные транспортные средства, а не только автомобили.

2. В вопросе не предполагалось, что транспортные средства не должны быть наземными транспортными средствами. И если на то пошло, вы делаете много предположений о том, что вообще делает Vehicle.terrain.