Проблема наследования в JavaScript - PullRequest
4 голосов
/ 06 июня 2011

У меня есть следующая иерархия классов:

  • Хранение
    • Коллекция
      • EixoCollection
      • OfertaCollection

И у меня есть следующий код:

var ofertaCollection = new OfertaCollection();
var eixoCollection = new EixoCollection();

ofertaCollection.set('mykey', 'myvalue');
alert(eixoCollection.get('mykey')); // it returns 'myvalue', should return nothing

Проблема в том, что ofertaCollection и eixoCollection имеют свойства, ссылающиеся друг на друга.

Следуйте за классами:

/**
 * Storage
 * 
 * @returns {Storage}
 */
function Storage(){

    this.storage = []; // itens that have a key

    // sets key
    this.set = function(key, value){
        this.storage[key] = value;
    }

    // gets key
    this.get = function(key){
        return this.storage[key];
    }
}

/**
 * Collection
 * 
 * @returns {Collection}
 */
function Collection(){

}
Collection.prototype = new Storage();

/**
 * EixoCollection
 * 
 * @returns {EixoCollection}
 */
function EixoCollection(){
}
EixoCollection.prototype = new Collection();

/**
 * OfertaCollection
 * 
 * @returns {OfertaCollection}
 */
function OfertaCollection(){
}
OfertaCollection.prototype = new Collection();

В чем проблема?

Ответы [ 3 ]

2 голосов
/ 07 июня 2011

Во-первых, я предлагаю два изменения в вашем коде (которые будут использоваться в примерах): this.storage должен быть объектом {}, так как похоже, что вы никогда не используете его в качестве массива. Кроме того, get и set должны быть в прототипе, в противном случае новый экземпляр этих методов будет создан для каждого объекта экземпляра (если только умный компилятор не оптимизирует их, но мы не будем так много предполагать).

Решение 1: вы можете выполнить квази-наследование, при этом только ваши хранилища методы предоставляются наследующим классам, но не хранилище объект :

function Storage(){}
storage.prototype = {
    get: function(key){
        return this.storage[key];
    },
    set: function(key, value){
        this.storage[key] = value;
    }
};

function Collection(){
    this.storage = {};
}
Collection.prototype = Storage.prototype; // quasi-inheritance

function EixoCollection(){}
EixoCollection.prototype = new Collection();

function OfertaCollection(){}
OfertaCollection.prototype = new Collection();

var ofertaCollection = new OfertaCollection();
var eixoCollection = new EixoCollection();

ofertaCollection.set('mykey', 'myvalue');
alert(eixoCollection.get('mykey')); // undefined

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

Collection.prototype = new Storage(); // real inheritance

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

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

1 голос
/ 07 июня 2011

Вот очень быстрое решение - измените:

function Collection(){
   // assuming you're doing some initialization here, referencing "this"
}
Collection.prototype = new Storage();

на

function Collection(){
    var that = new Storage();
    // initialize whatever's necessary, using "that"
    return that;
}

или, если вы не выполняете инициализацию, просто:

function Collection(){
    return new Storage();
}

Рабочий пример здесь.

Это превращает Collection в фабрику Storage, что предотвращает повторное использование тех же Storage объектов в потомках.

1 голос
/ 06 июня 2011

Проблема состоит в том, что оба ваших объекта коллекции совместно используют один и тот же объект Storage.

var c1 = new OfteraCollection().prototype.prototype;
var c2 = new ExioCollection().prototype.prototype;
console.log(c1 === c2); // true

Чтобы исправить это, вы можете выбросить все вместе Collection и создать каждый из ваших объектов коллекцииих Storage как их прототип.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...