Блог веб разработки статьи | видеообзоры | исходный код

Блог веб разработки статьи | видеообзоры | исходный код

webfanat вконтакте webfanat youtube

ООП в javascript

ООП в javascript

Доброго времени суток дорогие друзья! Тема сегодняшней статьи 'ООП в javascript'. Рассмотрим основные возможности которые предоставляет язык js для объектно ориентированного программирования. Поехали!

Для того чтобы создать класс в javascript нужно написать так:

class User{

 }

Здесь мы инициализировали класс с названием 'User'. Подобным образом инициализация происходит во многих языках программирования.

Внутри себя класс может содержать некие свойства и методы. Давайте их добавим!

class User{
      name;
      age;

      constructor(name, age){
        this.name = name;
        this.age = age;
      }

      getName(){
        return this.name;
      }

       getAge(){
        return this.age;
      }

      setAge(age){
        this.age = age;
      }
    }

 
    var user1 = new User('Андрей', 26),
        user2 = new User('Алена', 23);

    console.log(user1.getName(), user1.getAge());
    user2.setAge(24);
    console.log(user2.getName(), user2.getAge());

Теперь рассмотрим что мы имеем в классе. Два свойства 'name' и 'age' без указанного у них значения. Конструктор (constructor()) - метод который вызывается при создании объекта класса. Обратите внимание что в конструктор мы передаем два аргумента и их значения присваиваем нашим свойствам класса. Метод getName() возвращает значение свойства name а getAge() значение свойства age. setAge() служит для изменения свойства age. Я думаю здесь ничего сложного нет.

Далее мы создаем два объекта (пользователя) user1 и user2. И затем играемся с методами класса User выводя данные в консоль. Следует отметить, что сейчас к свойствам класса можно обращаться напрямую, пример:

console.log(user1.name);
user1.name = 'Аркадий';
console.log(user1.name);

Здесь мы обратились к свойству name и затем просто переопределили его. Так как свойства name и age являются открытыми к ним можно получать прямой доступ через объект. И это не есть хорошо. Во многих языках программирования поддерживающих ООП есть так называемые модификаторы доступа(public, protected, private) позволяющие ограничивать доступ к свойствам или методам, но в javascript подобного функционала еще пока не реализовано. И это может стать настоящей проблемой!

И все же модификатор доступа private в javascript можно реализовать подобным образом:

class User{
   #name;
   #age;

   constructor(name, age){
     this.#name = name;
     this.#age = age;

   }


   getName(){
     return this.#name;
   }

   getAge(){
     return this.#age;
   }

   setAge(age){
     this.#age = age;
   }
 }

 var user = new User('Андрей', 26);

Нужно просто к названию свойства добавить знак решетки(#). Теперь свойства name и age класса User защищены от прямого доступа. Проверим:

console.log(user.name);
console.log(user.#name);
console.log(user['#name']);

Любые попытки получить значение свойства #name будут тщетны. Точно так же мы не сможем переопределить данное свойство за пределами класса User и это уже хоть какая то защита от прямого доступа. Подобным образом мы можем ограничивать доступы для методов.

class User{
      #name;
      #age;

      constructor(name, age){
        this.#name = name;
        this.#age = age;
        this.#create();
      }

      #create = function(){
        console.log('Добавлен новый пользователь ' + this.#name);
      }

      getName(){
        return this.#name;
      }

      getAge(){
        return this.#age;
      }

      setAge(age){
        this.#age = age;
      }
    }

    var user = new User('Андрей', 26);

В данном случае метод #create будет защищен от внешнего вызова за пределами класса User.

user.create();
user.#create();
user['#create']();

Выводится ошибка - значит все работает! Едем дальше.

На очереди, статические методы и свойства. Их реализация ничем не отличается от многих языков поддерживающих ООП.

class User{
   #name;
   #age;
   static #users = [];

   constructor(name, age){
     this.#name = name;
     this.#age = age;
     User.#users.push({"name": this.#name, "age": this.#age});
     this.#create();
   }

   #create = function(){
     console.log('Добавлен новый пользователь ' + this.#name);
   }

   getName(){
     return this.#name;
   }

   getAge(){
     return this.#age;
   }

   setAge(age){
     this.#age = age;
   }

   static getUsers(){
     return User.#users;
   }
 }

 var user1 = new User('Андрей', 26),
     user2 = new User('Алена', 23);

  console.log(User.getUsers());

Здесь мы реализовали закрытое статическое свойство #users которое представляет из себя массив, в него записываются объекты с информацией о добавленных пользователях. Значение свойства возвращается с помощью статического метода getUsers(). Так как статические свойства и методы принадлежат не к объекту а классу, мы обращаемся к ним через класс, в нашем случае User. Как видите здесь все довольно просто.

Теперь сделаем наш класс User абстрактным.

class User{
     #name;
     #age;
     static #users = [];

     constructor(name, age){
       if (new.target === User) {
         throw new TypeError("Нет доступа к абстрактному классу!");
       }
       this.#name = name;
       this.#age = age;
       User.#users.push({"name": this.#name, "age": this.#age});
       this.#create();
     }

     #create = function(){
       console.log('Добавлен новый пользователь ' + this.#name);
     }

     getName(){
       return this.#name;
     }

     getAge(){
       return this.#age;
     }

     setAge(age){
       this.#age = age;
     }

     static getUsers(){
       return User.#users;
     }
   }

Для этого нам необходимо в конструкторе записать условие которое будет проверять реализацию новых объектов. В нашем случае, если создаваемый объект будет принадлежать классу User то мы выкинем исключение (throw new TypeError("Нет доступа к абстрактному классу!")) и в конечном итоге класс не будет реализован. Давайте это проверим:

var user = new User('Андрей', 26);

Здесь при попытке создать новый объект класса User выводится ошибка 'Нет доступа к абстрактному классу!'. То есть все работает как надо! Если кто не понял то абстрактный класс - это класс не имеющий прямой реализации, однако его методы и свойства можно использовать через другой класс с помощью наследования которое мы сейчас рассмотрим.

Создадим еще один класс 'Programmer' и зададим ему родителя.

class Programmer extends User {
    constructor(name, age){
      super(name, age);
    }
  }

Родительский класс задается через ключевое слово 'extends' и как вы наверное уже догадались это наш абстрактный класс User. Для того чтобы наследовать все свойства и методы User в классе Programmer необходимо вызвать конструктор родительского класса через ключевое слово super(). И теперь можно проверить.

var prog = new Programmer('Андрей', 26);
console.log(prog.getAge());
console.log(Programmer.getUsers());

Здесь мы видим что объект класса Programmer успешно наследовал методы и свойства своего родителя - класса User. У особо любопытных и внимательных программеров может возникнуть логичный вопрос, а что если в дочернем и родительском классе используются открытые методы и свойства с одинаковыми названиями. Рассмотрим пример:

class Programmer extends User {
    #name;
    constructor(name, age, spec){

      super(name, age);
      this.#name = spec;
    }

    getNameUser(){
      return super.getName();
    }

    getName(){
      return this.#name;
    }


  }

  var prog = new Programmer('Андрей', 26, 'Программист php');
  console.log(prog.getNameUser());
  console.log(prog.getAge());
  console.log(prog.getName());
  console.log(Programmer.getUsers());

Здесь в классе Programmer мы используем метод getName() который возвращает название специализации, но мы так же знаем что в родительском классе User есть такой же метод который возвращает имя пользователя. И для того чтобы вызвать метод getName() из родительского класса мы используем ключевое слово super в новом методе getNameUser() который в свою очередь возвращает имя пользователя. Через ключевое слово super мы также может обращаться к свойствам родительского класса. Только важно помнить что свойства и методы к которым мы обращаемся должны быть открытыми(то есть без знака #).

В завершение данной статьи рассмотрим реализацию интерфейсов в javascript.

function interfaceGetNameUser(obj){
      var getNameUser = function(){
        // требует реализовать в классе метод getName()
      }
      if(!((typeof obj['getNameUser']) === "function")){
             throw new TypeError("Требуется реализация метода getNameUser()");
      }
    }

  class Programmer extends User {
    #name;

    constructor(name, age, spec){
      super(name, age);
      interfaceGetNameUser(this);
      this.#name = spec;
    }

    getNameUser(){
      return super.getName();
    }

    getName(){
      return this.#name;
    }
  }

  var prog = new Programmer('Андрей', 26, 'Программист php');
  console.log(prog.getNameUser());
  console.log(prog.getAge());
  console.log(prog.getName());
  console.log(Programmer.getUsers());

Интерфейсы в js можно реализовать за счет использования обычных функций. В нашем случае создан интерфейс с названием interfaceGetNameUser() который проверяет наличие в классе метода getNameUser(). Если данного метода по какой то причине не будет реализовано, то нам вернется исключение(ошибка) - 'Требуется реализация метода getNameUser()'.

Вот в принципе и все что я хотел вам рассказать про ООП в javascript. Надеюсь данная статья оказалась для вас полезной и познавательной. Не забывайте подписываться в группу Вконтакте и переходите на канал Youtube.

С вами был Грибин Андрей. Желаю вам успехов и удачи!

Оцените статью:

Статьи

Комментарии

Внимание!!! Все комментарии проходят модерацию перед публикацией!

В данном разделе пока нет комментариев!

Реклама

Запись экрана

Данное расширение позволяет записывать экран и выводит видео в формате webm