2013-05-03 3 views
0

Я пытаюсь понять шаблон модуля с добавленным наследованием. Я исхожу из университетского опыта, в основном с Java в моем багажнике, но я работаю с веб-технологиями около десяти лет. Я всего лишь год на JavaScript, хотя ...Grasping «OOP» JavaScript: шаблон модуля с наследованием

В любом случае, я пытаюсь использовать простой наследование (.prototype). С объекта People вы можете добавить Gentleman, а затем перечислите их, используя их метод .toString(). A Gentleman является ребенком до Human. Все прошло хорошо, пока я не реализовал «абстрактный» Human, но теперь код не будет работать.

Прокомментируйте, что считается моим кодом. Я хотел бы остаться с модулем/прототипом, хотя, но что я делаю неправильно? Я также слушал бы то, что this означает в разных контекстах. I.e., в People Я могу использовать частный _people напрямую, но в подмодулях я должен использовать this._name --why?

var People = People || {}; 

People = (function() { 
    var People = function(){ 
     this._people = []; 
    }; 

    var addGentleman = function (name) { 
     this._people.push(new People.Gentleman(name)); 
    }; 

    var getList = function() { 
     var temp = []; 

     for (var i = 0; i < this._people.length; i++) { 
      temp.push(this._people[i].toString()); 
     } 

     return temp; 
    }; 

    People.prototype.constructor = People; 
    People.prototype.addGentleman = addGentleman; 
    People.prototype.getList = getList; 

    return People; 
})(); 

People.Human = (function() { 
    var Human = function (name, hasLadyParts) { 
     this._name = name; 
     this._hasLadyParts = hasLadyParts; 
    }; 

    var hasLadyParts = function() { 
     return this._hasLadyParts; 
    }; 

    var toString = function() { 
     var str = this._name; 
     if (!this._hasLadyParts) str += ' no'; 
     return str + ' lady parts.'; 
    }; 

    Human.prototype.constructor = Human; 
    Human.prototype.hasLadyParts = hasLadyParts; 
    Human.prototype.toString = toString; 

    return Human; 
})(); 

People.Gentleman = (function() { 
    var Gentleman = function (name) { 
     People.Human.call(this, name, false); 
    } 

    var toString = function() { 
     return 'Mr.' + People.Human.toString(); 
    }; 

    // Gentleman.prototype = Object.create(People.Human.prototype); 
    Gentleman.prototype.constructor = Gentleman; 
    Gentleman.prototype.toString = toString; 

    return Gentleman; 
})(); 

$(function() { 
    var people = new People(); 
    people.addGentleman('Viktor'); 
    people.addGentleman('Joakim'); 
    var list = people.getList(); 
    var $ul = $('#people'); 

    for (var i = 0; i < list.length; i++) { 
     $ul.append('<li>' + list[i] + '</li>'); 
    } 
}); 

Fiddle: http://jsfiddle.net/5CmMd/5/

Edit: Я обновил код и немного доделать. Если я получу эту работу, я думаю, что я понимаю большую часть дизайна. Этот пример также будет работать как простой учебник для будущих программистов ООП, посещающих территорию JavaScript, я думаю.

+0

Можете вы дать ссылку на описание рисунка? Я вижу ряд вещей, которые не будут работать, но Id скорее выражает это с точки зрения шаблона, на который вы работаете. –

+0

Этот рисунок на самом деле не очень хорошо описывается. Я пытаюсь совместить то, что мне кажется правильным, и то, что считается приемлемым в обсуждениях JS. Одна очень быстрая попытка по этой схеме: http://stackoverflow.com/questions/8683125/combining-inheritance-with-the-module-pattern Но, черт возьми, не стесняйтесь изменять то, что вы хотите, и я могу прочитать большинство объяснений если они четко определены. :) – Viktor

ответ

1

Я думаю, что основная проблема заключается в прототипе джентльменов. Для одного перезаписи прототипа, котор вы унаследованный от человека, для других вы используете = вместо: присвоить функции :)

Попробуйте это:

var People = People || {}; 

People = (function() { 
    var _people = []; 

    var People = function(){}; 

    var addGentleman = function (name) { 
     _people.push(new People.Gentleman(name)); 
    }; 

    var getList = function() { 
     var temp = []; 

     for (var i = 0; i < _people.length; i++) { 
      temp.push(_people[i].toString()); 
     } 

     return temp; 
    }; 

    People.prototype = { 
     constructor: People, 
     addGentleman: addGentleman, 
     getList: getList 
    }; 

    return People; 
})(); 

People.Human = (function() { 
    this._name; 

    var Human = function (name) { 
     this._name = name; 
    }; 



    Human.prototype = { 
     constructor: Human, 
    }; 

    return Human; 
})(); 

People.Gentleman = (function() { 

    var Gentleman = function (name) { 
     People.Human.call(this, name);  
    } 

    var toString = function() { 
     return 'Mr. ' + this._name; 
    }; 

    Gentleman.prototype = Object.create(People.Human.prototype); 


    Gentleman.prototype.constructor = Gentleman; 
    Gentleman.prototype.toString = toString; 

    return Gentleman; 
})(); 

$(function() { 
    var people = new People(); 
    people.addGentleman('Viktor'); // this is me 
    people.addGentleman('Joakim'); // and my friend! 
    var list = people.getList(); 
    var $ul = $('#people'); 

    for (var i = 0; i < list.length; i++) { 
     $ul.append('<li>' + list[i] + '</li>'); 
    } 
}); 

Вы можете увидеть, что я добавил новый toString для объекта прототипа, а не перезаписывать то, что уже есть. Я не знаю, имеет ли образец более хороший способ сделать это (я не знаком с ним).

Вы могли бы это сделать, если это представляется более целесообразным:

Gentleman.prototype = Object.create(People.Human.prototype, 
{ 
    constructor : { configurable: true, get : function() { return Gentleman } }, 
    toString : { configurable: true, get : function() { return toString } } 
}); 
+0

Ага, поэтому я должен использовать нотацию 'prototype.', а не' prototype = {} ', потому что тогда я переписываю? – Viktor

+0

yup - поэтому, когда вы выполняете второе назначение, он просто перезаписывает ссылку на объект, которую вы установили в предыдущей строке. Чтение ссылки zeroflags, вы также можете добавить дополнительные свойства, используя object.create() - плохое обновление с примером –

+0

Хорошо! Я обновил свой пример еще одним методом «Человек», но это не абстрактно. Не хотите ли вы обновить мою скрипку, чтобы она работала? Я получаю перезапись, и поэтому я использую ваше первое решение. – Viktor

2
Gentleman.prototype = Object.create(People.Human.prototype); 

Gentleman.prototype = { 
    constructor = Gentleman, 
    toString = toString 
}; 

Должно быть constructor: Gentleman, .... Кроме того, вы дважды назначаете prototype и, следовательно, перезаписываете его. Это имеет побочный эффект, который Gentleman больше не наследует от Human. Вы должны добавить к нему:

Gentleman.prototype.toString = toString; 

Или добавьте свойства с Object.create() вызова. see reference

Что касается this:

Вы можете использовать _people напрямую, потому что это переменная. Все экземпляры People имеют одинаковый список людей.

При вызове функции как метода объекта this относится к самому объекту. Поскольку каждый Human должен иметь свое собственное имя this._name, это имя this ^^ человека. Таким образом, aGentleman.toString() вернет имя точно джентльмен.

People.Human = (function() { 
    this._name; //<- does not do anything. 
+0

Тогда как я могу сделать конструктор (args) {super (args); // Джентльменский код} '? И почему базовый «класс» «Люди» не должен использовать «это»? – Viktor

+0

@ Viktor Вопрос 1: Вы уже это делаете. Я не понимаю вопроса. Вопрос 2: Вы знаете Java, поэтому вы знаете разницу между полем и переменной. С 'this' вы получаете доступ к полю. '_people' - переменная. – zeroflagL

+0

1. Но если я удалю 'Gentleman.prototype = Object.create (People.Human.prototype),' он все равно не будет работать. Вы представите обновленную скрипку? :) – Viktor

Смежные вопросы