Недостатки классического наследования
Классическое наследование часто используется в JavaScript для создания классов прототипом. Вы создаете объект, а затем добавляете к нему свойства и функции. Затем вы хотите создать второй объект, который наследует свойства и функции первого объекта. Хотя можно использовать классическое наследование для создания этого второго объекта, вы должны знать детали реализации, чтобы правильно наследовать от него, чтобы не переопределять свойства в цепочке. Вот где Module Pattern действительно проявляет себя как более безопасная и инкапсулирующая альтернатива.
Переходя к примеру, давайте определим класс Bank.
//constructor for new class function Bank(){ this.isOpen = true; } Bank.prototype.close = function(){ console.log('Closing up...') this.isOpen = false; } Bank.prototype.isBankOpen = function(){ return this.isOpen }
Теперь, когда класс Bank создан, давайте создадим новый класс Branch, который наследуется от Bank.
//constructor for new class function Branch(){ Bank.call(this); } //inheriting methods from Bank Branch.prototype = Object.create(Bank.prototype) Branch.prototype.constructor = Branch; Branch.prototype.closeBranch = function(){ console.log('closing branch...') this.isOpen = false; } Branch.prototype.isBranchOpen = function(){ return this.isOpen; }
На этом этапе мы создали новый класс Branch, который наследует close () и getOpenStatus () от класса Bank через Object.create. Так в чем же проблема с использованием этого наследования?
К сожалению, мы сталкиваемся с ситуацией, когда свойство this.isOpen класса Branch конфликтует со свойством this.isOpen класса Bank. Объект ветви используется как глобальное пространство имен и конфликтует со свойством isOpen унаследованного класса Bank.
console.log(branch.getOpenStatus()); //true branch.closeBranch(); //Closing bank console.log(branch.getOpenStatus()); //false
К счастью, шаблон модуля может помочь решить эту проблему глобального конфликта пространств имен.
function Bank() { var isOpen = true function close() { console.log('closing bank...') isOpen = false } function isBankOpen() { return isOpen } return { close: close, isBankOpen: isBankOpen } } function Branch() { var branch = {} var isOpen = true branch.__proto__ = Bank() branch.closeBranch = function closeBranch() { console.log('closing branch!') isOpen = false } branch.isBranchOpen = function isBranchOpen() { return isOpen } return branch }
Используя шаблон модуля, мы удаляем конфликты глобального пространства имен из цепочки прототипов. Теперь у классов Bank и Branch есть собственные свойства isOpen.
var locationA = Branch() console.log(locationA.isBankOpen()); locationA.closeBranch(); console.log(locationA.isBranchOpen());; console.log(locationA.isBankOpen());
Вышеприведенный шаблон модуля дает вам два отдельных объекта без конфликтов свойств со всеми преимуществами наследования.