Недостатки классического наследования

Классическое наследование часто используется в 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());

Вышеприведенный шаблон модуля дает вам два отдельных объекта без конфликтов свойств со всеми преимуществами наследования.