g1er / Andrew

0 stars 0 forks source link

Getters and Setters #10

Closed IgorKulishov closed 6 years ago

IgorKulishov commented 6 years ago

Getters and Setters of Classes:

В прошлой теме мы изучили синтакс нового JavaScript ES6 - как создавать классы содержащие методы и свойства, а так же образовывать новые объекты используя эти классы.

Мы продолжим изучать дальше различные виды этих методов. На этот раз мы изучим как читать и менять/задавать внутренние свойства объектов при помощи getter и setter соотеветственно. Итак приведу пример:

//определение класса
class User {
  constructor(firstName) {
    this.firstName = firstName;
  }
  // getter - метод для получения/чтения значений внутренних свойства (обозначается словом "get")
  get fullName() {
    return this.firstName;
  }
  // "set" - setter - метод для задания значений внутренных свойств (обозначается словом "set")
  set fullName(newValue) {
    this.firstName = newValue;
  }
};
var user = new User("Robin");
//обращаемся к гетеру
alert(user.fullName);
//обращаемся к сетеру
user.fullName = "Bobin";
//обращаемся еще раз к гетеру и читаем новые свойства
alert(user.fulName);

Основные моменты: 1) getter обозначаются при помощи слова get перед методом 2) setter обозначаются при помощи слова set перед методом 3) при обращении к гетеру нового объекта не используем скобки вконце getter метода 4) так же при задании значений созданного объекта через setter мы присваиваем методу setter новое значение как будто бы обычному свойству объекта: user.fullName = "Bobin";

Обращаю внимание мы не помещаем новое значение как аргумент внутри скобок метода setter как могло бы показаться (т.е. неправильно было бы: user.fullName("Bobin") )

Кроме того обращаю внимание что, называние getter и setter не обязательно должно быть одинаковым.

IgorKulishov commented 6 years ago

Для прароботки упражнений можешь использовать консоли браузеров (все современные браузеры поддерживают JavaScript ES6) Кроме того есть такие online песочницы: https://jsbin.com/junibalupu/4/edit?html,css,js,output

g1er commented 6 years ago

Значит, как я понял, prototype у нас для добавления новых свойств и методов, а get и set для получения и изменения их значений. А как мне изменить значение новосозданного через prototype свойства или метода через set? Например, я создаю новое свойство через User.prototype, а потом мне надо его значение изменить. Как мне это осуществить?

IgorKulishov commented 6 years ago

Я обновил свой ответ и подкрепил примерами.

Да действительно как ты и сказал при помощи prototype можно создать свойства и методы объекта (в классическом JS ES5), а так же определить/переопределить их значения, но я решил дать более расширенный ответ.

  1. prototype это прежде всего способ унаследования и совместного использования свойств и методов объектов в JavaScript (способ передачи наследственности типа ген ДНК своего рода ). Если объект B создан от объекта A, то prototype B будет содержать prototype A со всеми унаследованными методами и свойствами объекта A ( вся наследственная цепочка будет содержаться в prototype B ). В тоже время свойства prototype можно перезаписать или даже удалить.

  2. Сам объект Object в JS так же имеет prototype. Предлагаю в консоли набрать Object.prototype и раскрыть его , ты увидешь там содержаться свойства и методы Object в том числе constructor, get, set и т.д.

  3. как ты знаешь в классическом JS ES5 и новом JS ES6 (ES2015) есть различия: А) В JS ES5 функция может быть конструктором для создания новых объектов. Так же ты знаешь что

    при помощи prototype можно добавить новые свойства или перезаписать существующие в конструктор,

    при этом все созданные от конструктора объекты унаследуют новые свойства и методы:

    function Animals(name) { this.name = name; }
    var cat = new Animals('cat');
    var dog = new Animals('dog');
    Animals.prototype.inhabitPlanet = 'Earth';
    Animals.prototype.jump = function(){ return 'jump ' + this.name; };

Prototype кроме того что помогают унаследовать и менять свойства, так же помогают оптимизировать использование памяти в JS т.к. созданные от конструктора объекты указывают в памяти браузера на тот же совместно используемый объект (что лучше чем просто копировать тоже самое несколько раз).

Б) В JS ES6 для подобия с объектными языками были определены class, constructor, get, set, что на самом деле только лишь синтаксис похожий на объектно-ориентрованные языки (Java и C++) и на самом деле под капотом используется все тот же prototype в котором определены объекты constructor, get, set и т.д. за разницей в том что это присвоение значений производится теперь при помощи встроенных методов.

В новом синтаксисе ВСЕ свойства определены внутри constructor , читаются при помощи get и задаются при помощи set, а методы определены при помощи синтексиса "myMethod() { // put here your functional part }

Однако нам ничего не мешает использовать все тот же ES5 и определить свойства и методы при помощи prototype:

//определим класс
class Animalz { 
  constructor(name) {
     this.name = name;
     this.breathGas = 'oxygen';
   }
  //определим метод класса
  eats() { return this.name + ' eats organic food';}
}
//используем стандартный prototype для определение нового метода
Animalz.prototype.lives = function() {
  return this.name + ' lives on the planet ' + this.inhabitantPlanet + ' and breaths ' + this.breathGas;
}
//используем prototype для определение свойства
Animalz.prototype.inhabitantPlanet = 'Earth'

var racoon = new Animalz('racoon');
racoon.lives();
racoon.eats();

Хотя возможно я ответил на твой вопрос, тем не менее я приведу еще примеры как можно так же использовать встроенный метод "defineProperty" для добавления свойств и методов в prototype.

В следующий главе мы рассмотрим синтакс ES6: "extend" которые позволяют создавать дочерние классы от родительского класса добавляя новые свойства и унаследуя все свойства и методы родительского класса.

Пример применения, через get/set , prototype и Object.defineProperty :

//определим методы в класса через get и set
class MyCount {
  constructor(num) {
    this.num = num;

  }
   get read() { return this.num };
   set add(x) { this.num  += x };
}
let myCounter = new MyCount(1)
myCounter.add = 3
console.log(myCounter.read);

//добавим новый метод через prototype
MyCount.prototype.multiply = function(y) {
   return this.num *= y;
}
myCounter.multiply(2);
console.log(myCounter.read)

//Используем Object.defineProperty встроенный метод JavaScript для добавления класса в prototype: 
// полное описание на официальном сайте: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Object.defineProperty(MyCount.prototype, "subtract", {
  set(subtract) {
    this.num -= subtract;
  }
});

var a = new MyCount(123);

a.add = 0;
a.subtract = 2
console.log(a.read); 

Добавь дополнительно свой метод любым способом

**Присылай вопросы

g1er commented 6 years ago

//ну, пусть будет квадратный корень MyCount.prototype.squareRoot = function(s) { return Math.sqrt(this.num)= s; } myCounter.squareRoot(4); console.log(myCounter.read);

g1er commented 6 years ago

хмм... знаешь, проверил это в консоли дебаггера, и он мне выдал такую ошибку: Identifier 'MyCount' has already been declared at <anonymous>:1:1 я вбил твой пример:

class MyCount {
  constructor(num) {
    this.num = num;

  }
   get read() { return this.num };
   set add(x) { this.num  += x };
}
let myCounter = new MyCount(1)
myCounter.add = 3
console.log(myCounter.read);

//добавим новый метод через prototype
MyCount.prototype.multiply = function(y) {
   return this.num *= y;
}
myCounter.multiply(2);
console.log(myCounter.read)

но и тут был тот же результат. что-то я не пойму, в чем нестыковка?

g1er commented 6 years ago

Я нашел в чем причина. Плюс видать я ещё и с синтаксисом напутал. Вот измененный вариант:

MyCount.prorotype.division = function(s) { return this.num /= s; }

myCounter.division(3); console.log(myCounter.read);

Тут при проверке в консоли все происходит нормально

IgorKulishov commented 6 years ago

Ошибка:

Identifier 'MyCount' has already been declared at <anonymous>:1:1

появляется когда дважды пытаешься определить один и тот же класс - не позволяет повторно опрелить класс с тем же названием в том же окне. Если ты хочешь переопределить класс, то пожалуйста переназови класс (дай другое название). Или открой другое окно.

g1er commented 6 years ago

Я так и понял. Я просто не разобрался в работе дебагера, думал надо каждый раз заново определять класс после каждого нажатия Enter

IgorKulishov commented 6 years ago

Предлагаю еще раз просмотреть, задать если есть вопросы. И если все понятно закрыть задание и перейти к следующему.