Полный цикл в digital

Свойства и методы доступа

Для опосредования доступа к свойствам класса в последних стандартах JavaScript была добавлена поддержка методов доступа - get и set. Сначала рассмотрим проблему, с которой мы можем столкнуться:

class Person{
constructor(name, age){
this.name = name;
this.age = age;
}
}
const tom = new Person("Tom", 37);
// 37
console.log(tom.age);  
tom.age = -15;
// -15
console.log(tom.age);

Класс Person определяет два свойства - name и age, значения которых мы можем получить или установить. Но что если мы передадим некорректные значения? Так, в примере выше свойству age передается отрицательное число, но возраст не может быть отрицательным.

Чтобы выйти из этой ситуации, мы можем определить приватное поле age, к которому можно было бы обратиться только из текущего класса. А для получения или установки его значения создать специальные методы:

class Person{
#ageValue = 1;
constructor(name, age){
this.name = name;
this.setAge(age);
}
getAge(){
return this.#ageValue;
}
setAge(value){ if(value>0 && value < 110) this.#ageValue = value; }
}
const tom = new Person("Tom", 37);
// 37
console.log(tom.getAge());  
tom.setAge(-15);
// 37
console.log(tom.getAge());

Теперь возраст хранится в приватном поле ageValue. При его установке в методе setAge() проверяется переданное значение. И установка происходит, если только передано корректное значение. А метод getAge() возвращает значение этой переменной.

Но есть и другое решение - применение методов доступа get и set:

// определение приватного поля
#field;
set field(value){
this.#field= value;
}
get field(){
return this.#field;
}

Оба метода - get и set имеют одинаковые названия. Как правило, они опосредуют доступ к некоторому приватному полю. Метод set предназначен для установки. Он принимает в качестве параметра новое значение. Далее в методе set мы можем выполнить ряд действий при установке.

Метод get предназначен для получения значения. Здесь мы можем определить какую-нибудь логику при возвращении значения.

Так, перепишем предыдущий пример с использованием get и set:

class Person{
#ageValue = 1;
constructor(name, age){
this.name = name;
this.age = age;
}
set age(value){
console.log(`Передано ${value}`);
if(value>0 && value < 110) this.#ageValue = value;
}
get age(){
return this.#ageValue;
}
}
const tom = new Person("Tom", 37);
console.log(tom.age);
tom.age = -15;
console.log(tom.age);

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

console.log(tom.age);

А не:

console.log(tom.age());

То есть при обращении tom.age фактически будет срабатывать метод get, который возвратит значение поля ageValue.

А при вызове:

tom.age = -15;

Будет срабатывать метод set, который получит передаваемое ему значение (здесь число -15) через единственный параметр. И далее в самом методе set мы можем решить, надо ли устанавливать это значение.

Свойства, доступные только для чтения

Выше применялись оба метода get и set, соответственно значение поля можно было и получить, и установить. Однако в реальност мы можем использовать только один из них. Например, мы можем оставить только метод get и тем самым сделать свойство доступным только для чтения.

Например, в изменим пример выше и сделаем свойство name доступным только для чтения:

class Person{
#age = 1;
#name;
constructor(name, age){
this.#name = name;
this.age = age;
}
//set name(value){ this.#name = value; }
get name(){ return this.#name; }
set age(value){ if(value>0 && value < 110) this.#age = value; }
get age(){ return this.#age; }
}
const tom = new Person("Tom", 37);
// Tom
console.log(tom.name);  
// Это ничего не даст
tom.name = "Bob";  
// Tom - значение не изменилось
console.log(tom.name);

В данном случае вместо общедоступного свойства name определена приватное поле #name. Его можно установить только из внутри класса, что мы и делаем в конструкторе класса. Однако из вне его можно только прочитать с помощью метода get. Поэтому попытка установки свойства ни к чему не приведет:

tom.name = "Bob";

Свойства только для установки

Также мы можем сделать свойство доступным только для записи, оставив только метод set. Например, добавим новое свойство id, которое будет доступно только для записи:

class Person{
#id;
constructor(name, age, id){
this.name = name;
this.age = age;
this.id = id;
}
set id(value){ this.#id = value;}
print(){
console.log(`id: ${this.#id}   name: ${this.name}   age: ${this.age}`);
}
}
const tom = new Person("Tom", 37, 1);
// id: 1   name: Tom   age: 37
tom.print();  
// устанавливаем значение свойства id
tom.id = 55; 
// id: 55   name: Tom   age: 37 
tom.print(); 
// undefined - значение свойства id нельзя получить 
console.log(tom.id);

Здесь определено свойство id, которое устанавливает значение приватного поля #id. Но поскольку метода get для этого свойства не определено, то при попытке получить значение свойства id, мы получим undefined:

// undefined - значение свойства id нельзя получить
console.log(tom.id);

Свойства без обращения к полям

Стоит отметить, что методы get и set необязательно должны обращаться к приватным или неприватным полям. Это могут быть и вычисляемые свойства:

class Person{
constructor(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
get fullName(){ return `${this.firstName} ${this.lastName}` }
}
const tom = new Person("Tom", "Smith");
// Tom Smith
console.log(tom.fullName);

В данном случае свойство для чтения fullName возращает фактически объединение двух свойств - firstName и lastName.

Подобным образом можно определить и свойство для записи:

class Person{
constructor(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
get fullName(){ return `${this.firstName} ${this.lastName}` }
set fullName(value){ 
[this.firstName, this.lastName] = value.split(" ");
}
}
const tom = new Person("Tom", "Smith");
// Tom Smith
console.log(tom.fullName);  
tom.fullName = "Tomas Jefferson";
// Jefferson
console.log(tom.lastName);

В данном случае метод set свойства fullName в качестве параметра получает некоторую строку и с помощью ее метода split разбивает по пробелу и получает массив подстрок, которые были разделены пробелом. То есть, теоретически мы рассчитываем, что будет передано что-то наподобие Tom Smith, а после разделения по пробелу свойство firstName получит значение Tom, а свойтсво lastName - значение Smith. Стоит отметить, что для простоты и целй демонстрации здесь мы не рассматриваем исключительные ситуации, когда передается пустая строка или строка, которая не делится по пробелу на две части и т.д.

В итоге при получении нового значения:

tom.fullName = "Tomas Jefferson";

Метод set разобьет его по пробелу, и первый элемент массива будет передан свойству firstName, а второй - свойству lastName.

Заполните форму уже сегодня!
Для начала сотрудничества необходимо заполнить заявку или заказать обратный звонок. В ответ получите коммерческое предложение, которое будет содержать индивидуальную стратегию с учетом требований и поставленных задач
Работаем по будням с 9:00 до 18:00. Заявки, отправленные в выходные, обрабатываем в первый рабочий день до 12:00.
Спасибо, ваш запрос принят и будет обработан!
Эйч Маркетинг