Javascript: разрешение «виртуальной» функции в базовом классе для создания экземпляра подкласса - PullRequest
2 голосов
/ 23 октября 2010

У меня есть следующая объектная модель, которую я хочу получить - я бился головой о бит клона! Это возможно? Кажется, я не могу получить доступ к конструктору SubClass из базового класса без жесткого его кодирования.

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

Возможно ли это без переопределения метода clone () в каждом подклассе?

/*
Application specific subclass:
*/
function SubClass_Operation1()
{
  BaseOperationClass.apply(this, arguments); // Call inherited constructor

  this.action = function()
  {
    this.manager.addToQueue(this.clone({changeValue:1}));
    this.manager.addToQueue(this.clone({changeValue:2}));
    this.manager.addToQueue(this.clone({changeValue:3}));
  }
}
SubClass.prototype = new BaseOperationClass;

// More of these defined for each operation
...

/*
Base class containing all common functionality
*/
function BaseOperationClass(manager)
{
  this.manager = manager;

  // Placeholder for virtual action() function
  this.action = function()
  {
  }

  this.clone = function(mods)
  {
    var res = ?????? // Should create exact copy of current SubClass

    res.applyModifications(mods);
  }

  this.applyModifications(mods)
  {
    ...
  }

  // Lots of common functionality 
  ...
}

1 Ответ

0 голосов
/ 08 марта 2016

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

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

Вот пример в бегущем фрагменте:

function Base() {
    this.type = "base";
}

Base.prototype = {
    clone: function () {
        var c = new this.constructor();
        // let clone initialize itself from the original
        c.init(this);
        return c;
    },
    setName: function(name) {
        this.name = name;
    },
    init: function(obj) {
        // copy over name instance data
        this.name = obj.name;
    }
}

// set .constructor property for use with .clone()
Base.prototype.constructor = Base;

function Derived() {
    Base.call(this);
    this.type = "derived";
}

// inherit from Base
Derived.prototype = Object.create(Base.prototype);
Derived.prototype.setOccupation = function(occupation) {
    this.occupation = occupation;
}
Derived.prototype.init = function(obj) {
    // let base object init itself
    Base.prototype.init.call(this, obj);
  
    // copy over our own instance data
    this.occupation = obj.occupation;
}

// set .constructor property for use with .clone()
Derived.prototype.constructor = Derived;

var x = new Derived();
x.setName("Bob");
x.setOccupation("Engineer");
var xx = x.clone();

var y = new Base();
y.setName("Alice");
var yy = y.clone();

log(x !== xx)
log(x);
log(xx);
log(y);
log(yy)

// function just for output in snippet
function log(a) {
    var div = document.createElement("div");
    if (typeof a === "object") {
        a = JSON.stringify(a);
    }
    div.innerHTML = a;
    document.body.appendChild(div);
}
...