Для чего нужны геттеры и сеттеры? [дубликат]
Никак не могу понять для чего применять геттеры и сеттеры. Понятно, что сеттеры задают значение, а геттеры для получение, но главный вопрос — где и для чего это применять? Можете объяснить человеческим языком
Отслеживать
задан 25 янв 2022 в 20:06
113 7 7 бронзовых знаков
При get можно возвращать измененной значение или совершать еще какое событие, к примеру у тебя может быть приватное поле в каком то формате, а через группу get можно получать в различных форматах. Так же и c set можно к примеру добавить проверки и вызывать исключения.
26 янв 2022 в 2:31
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
@Andrey правильно сказал, но также у них есть ещё одна практическая особенность. При их правильном подходе, и использовании private для полей. Мы точно можем сказать, что значения задаются через set и получается через get. А значит если у нас ошибки в коде, их намного легче отлаживать, поскольку мы точно знаем что значения задаются только через них, нам не надо копатся в другом коде
Отслеживать
ответ дан 26 янв 2022 в 5:10
659 4 4 серебряных знака 20 20 бронзовых знаков
-
Важное на Мете
Связанные
Похожие
Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.3.2953
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Свойства — геттеры и сеттеры
Первый тип это свойства-данные (data properties). Мы уже знаем, как работать с ними. Все свойства, которые мы использовали до текущего момента, были свойствами-данными.
Второй тип свойств мы ещё не рассматривали. Это свойства-аксессоры (accessor properties). По своей сути это функции, которые используются для присвоения и получения значения, но во внешнем коде они выглядят как обычные свойства объекта.
Геттеры и сеттеры
Свойства-аксессоры представлены методами: «геттер» – для чтения и «сеттер» – для записи. При литеральном объявлении объекта они обозначаются get и set :
let obj = < get propName() < // геттер, срабатывает при чтении obj.propName >, set propName(value) < // сеттер, срабатывает при записи obj.propName = value >>;
Геттер срабатывает, когда obj.propName читается, сеттер – когда значение присваивается.
Например, у нас есть объект user со свойствами name и surname :
let user = < name: "John", surname: "Smith" >;
А теперь добавим свойство объекта fullName для полного имени, которое в нашем случае «John Smith» . Само собой, мы не хотим дублировать уже имеющуюся информацию, так что реализуем его при помощи аксессора:
let user = < name: "John", surname: "Smith", get fullName() < return `$$`; > >; alert(user.fullName); // John Smith
Снаружи свойство-аксессор выглядит как обычное свойство. В этом и заключается смысл свойств-аксессоров. Мы не вызываем user.fullName как функцию, а читаем как обычное свойство: геттер выполнит всю работу за кулисами.
На данный момент у fullName есть только геттер. Если мы попытаемся назначить user.fullName= , произойдёт ошибка:
let user = < get fullName() < return `. `; >>; user.fullName = "Тест"; // Ошибка (у свойства есть только геттер)
Давайте исправим это, добавив сеттер для user.fullName :
let user = < name: "John", surname: "Smith", get fullName() < return `$$`; >, set fullName(value) < [this.name, this.surname] = value.split(" "); >>; // set fullName запустится с данным значением user.fullName = "Alice Cooper"; alert(user.name); // Alice alert(user.surname); // Cooper
В итоге мы получили «виртуальное» свойство fullName . Его можно прочитать и изменить.
Дескрипторы свойств доступа
Дескрипторы свойств-аксессоров отличаются от «обычных» свойств-данных.
Свойства-аксессоры не имеют value и writable , но взамен предлагают функции get и set .
То есть, дескриптор аксессора может иметь:
- get – функция без аргументов, которая сработает при чтении свойства,
- set – функция, принимающая один аргумент, вызываемая при присвоении свойства,
- enumerable – то же самое, что и для свойств-данных,
- configurable – то же самое, что и для свойств-данных.
Например, для создания аксессора fullName при помощи defineProperty мы можем передать дескриптор с использованием get и set :
let user = < name: "John", surname: "Smith" >; Object.defineProperty(user, 'fullName', < get() < return `$$`; >, set(value) < [this.name, this.surname] = value.split(" "); >>); alert(user.fullName); // John Smith for(let key in user) alert(key); // name, surname
Ещё раз заметим, что свойство объекта может быть либо свойством-аксессором (с методами get/set ), либо свойством-данным (со значением value ).
При попытке указать и get , и value в одном дескрипторе будет ошибка:
// Error: Invalid property descriptor. Object.defineProperty(<>, 'prop', < get() < return 1 >, value: 2 >);
Умные геттеры/сеттеры
Геттеры/сеттеры можно использовать как обёртки над «реальными» значениями свойств, чтобы получить больше контроля над операциями с ними.
Например, если мы хотим запретить устанавливать короткое имя для user , мы можем использовать сеттер name для проверки, а само значение хранить в отдельном свойстве _name :
let user = < get name() < return this._name; >, set name(value) < if (value.length < 4) < alert("Имя слишком короткое, должно быть более 4 символов"); return; >this._name = value; > >; user.name = "Pete"; alert(user.name); // Pete user.name = ""; // Имя слишком короткое.
Таким образом, само имя хранится в _name , доступ к которому производится через геттер и сеттер.
Технически, внешний код всё ещё может получить доступ к имени напрямую с помощью user._name , но существует широко известное соглашение о том, что свойства, которые начинаются с символа «_» , являются внутренними, и к ним не следует обращаться из-за пределов объекта.
Использование для совместимости
У аксессоров есть интересная область применения – они позволяют в любой момент взять «обычное» свойство и изменить его поведение, поменяв на геттер и сеттер.
Например, представим, что мы начали реализовывать объект user , используя свойства-данные имя name и возраст age :
function User(name, age) < this.name = name; this.age = age; >let john = new User("John", 25); alert( john.age ); // 25
…Но рано или поздно всё может измениться. Взамен возраста age мы можем решить хранить дату рождения birthday , потому что так более точно и удобно:
function User(name, birthday) < this.name = name; this.birthday = birthday; >let john = new User("John", new Date(1992, 6, 1));
Что нам делать со старым кодом, который использует свойство age ?
Мы можем попытаться найти все такие места и изменить их, но это отнимает время и может быть невыполнимо, если код используется другими людьми. И кроме того, age – это отличное свойство для user , верно?
Давайте его сохраним.
Добавление геттера для age решит проблему:
function User(name, birthday) < this.name = name; this.birthday = birthday; // возраст рассчитывается из текущей даты и дня рождения Object.defineProperty(this, "age", < get() < let todayYear = new Date().getFullYear(); return todayYear - this.birthday.getFullYear(); >>); > let john = new User("John", new Date(1992, 6, 1)); alert( john.birthday ); // доступен как день рождения alert( john.age ); // . так и возраст
Теперь старый код тоже работает, и у нас есть отличное дополнительное свойство!
В js геттеры и сеттеры это отдельные функции get, set? Как они работают?
В JS есть особый тип свойств — это свойства-аксессоры. Их особенность в том, что при обращении к этим свойствам вызываются функции, которые выполняют необходимую работу. Все взаимодействия со свойствами сводятся к двум операциям: получение значения из свойства и присваивание нового значения свойству. То есть, чтобы работать со свойством объекта, достаточно описать две операции: операцию получения значения из свойства и операцию сохранения значения в свойство. Это и есть геттеры и сеттеры. Геттер — занимается извлечением значения из свойства, а сеттер — сохранением значения. Для этого в JS есть специальный механизм, в котором ставится get перед геттером и set перед сеттером. Рассмотрим пример, в котором у нас есть пользователь с именем и фамилией:
const user = firstName: 'Ivan', lastName: 'Ivanov', >;
И мы хотим определить третье свойство, которое бы содержало полное имя. Оно зависит от имени и фамилии, поэтому, чтобы не дублировать данные, лучше всего подойдёт геттер:
const user = firstName: 'Ivan', lastName: 'Ivanov', get fullName() return `$this.firstName> $this.lastName>`; >, >; console.log(user.fullName); // => Ivan Ivanov
При обращении к свойству fullName вызывается геттер, который формирует результат и возвращает его. Также мы можем определить сеттер для этого свойства, функция будет обновлять данные о пользователе:
const user = firstName: 'Ivan', lastName: 'Ivanov', get fullName() return `$this.firstName> $this.lastName>`; >, set fullName(fullName) const [first, second] = fullName.split(' '); this.firstName = first; this.lastName = second; >, >; user.fullName = 'Petr Petrov'; console.log(user); // =>
При обновлении свойства, вызывается сеттер, внутри которого происходит вся необходимая работа и сохранение данных, если это необходимо.
Что такое геттеры и сеттеры в программировании
Это будет текст об архитектуре объектно-ориентированных программ. Это для тех, кто планирует серьёзно заниматься разработкой.
В объектно-ориентированном программировании многое основано на объектах — специальных «коробках» из данных и функций, которые работают в программе как единое целое. Внутри объекты могут быть устроены сложно, но снаружи из них торчат понятные «ручки» и «индикаторы» — то, через что другие части программы с этими объектами взаимодействуют.
Например, можно представить, что автомобиль — это объект: у него внутри много сложных деталей и связей между ними. Но снаружи всё относительно просто: руль, педали, переключатели, фары, спидометр, тахометр, индикатор температуры, уровня топлива и т. д. Чтобы этим управлять, нам не нужно знать внутреннее устройство машины, а достаточно изучить основные внешние функции.

Одно из понятий ООП — инкапсуляция, и в нём часто применяется такая идея:
доступ к внутренним данным объекта нельзя получить напрямую — это делается через специальные механизмы. Это нужно для того, чтобы другие части программы не могли нештатным образом повлиять на работу объекта.
Если говорить про автомобиль, то внутренние данные объекта — это объём бензина в миллилитрах, который поступает в двигатель на каждом такте работы. Водитель не может управлять этим напрямую и лить в двигатель сколько угодно бензина. Вместо этого он может нажать на педаль газа, а машина дальше сама рассчитает концентрацию бензина в воздушно-топливной смеси.
Такие механизмы доступа к данным через посредника называются геттеры и сеттеры.
Что такое геттер и сеттер
Эти слова пришли из английского от слов get (получать) и set (устанавливать).
Задача геттера — получить данные о чём-то внутри объекта и передать их наружу. Например, водитель не может постоянно заглядывать в бензобак и смотреть, сколько бензина. Вместо этого водитель смотрит на индикатор топлива — тот показывает, сколько бензина осталось в баке. Индикатор топлива — это геттер: он берёт данные из объекта (автомобиль) и отдаёт их тому, кто их попросил (водитель).
Сеттер работает иначе: он меняет значения внутри объекта. В примере с автомобилем педаль газа — это сеттер: в зависимости от силы нажатия она изменяет объём впрыска топлива в двигатель. Так производители защищают двигатель от нештатных ситуаций: даже при нажатии педали газа в пол в двигатель попадёт безопасное количество топлива.
Геттеры и сеттеры в программировании
Чаще всего в программировании эти инструменты используются как метод или интерфейс объекта: вы создаёте объект и указываете, что с ним можно делать. Поясним на примере.
Допустим, мы делаем голосовалку для интернет-магазина — люди выбирают, нравится им какой-то товар или нет. Одна из наших задач — сделать так, чтобы в коде программы ничто не могло напрямую влиять на значение счётчика. Всё, что мы разрешаем, — это увеличить счётчик на единицу или узнать текущее значение. Это избавит нас от ситуации, когда какая-то функция вдруг захочет накрутить счётчик сразу на 10 тысяч голосов. Чтобы так сделать, нам достаточно спрятать переменную счётчика в объект и там же объявить два метода — чтения (узнать результат) и записи (проголосовать, то есть увеличить строго на единицу). Для этого даже необязательно создавать отдельный класс. В JavaScript, например, это можно сделать за счёт стандартного замыкания, когда мы вкладываем одну функцию в другую.
// Объявляем новый объект-константу с помощью стрелочной функции const createCounter = () => < // Доступ к этой переменной возможен только внутри этой функции, снаружи поменять её не получится let count = 0; // Что возвращает функция return (< // Если вызван метод upvote(), увеличиваем переменную счётчика на 1 upvote: () =>count += 1, // Если вызван метод getVoteCount, возвращаем значение счётчика getVoteCount: () => count.toLocaleString() >); >; // Создаём новый объект на основе своего const counter = createCounter(); // Кликаем пару раз, увеличивая счётчик на единицу // Другим способом мы не сможем его изменить counter.upvote(); counter.upvote(); // Смотрим, что получилось в итоге (2) console.log(counter.getVoteCount());
А если в основной программе попробовать поменять значение переменной count, то ничего не изменится. А всё потому, что доступ к переменной count возможен только изнутри объекта и только двумя разрешёнными способами.
// ❌ Кажется, что это тоже сработает, но на самом деле значение счётчика не изменится
counter.count = 100
// На выходе всё так же будет число 2
console.log(counter.getCount());

Зачем они нужны
Основная задача геттеров и сеттеров — защитить данные внутри объекта, чтобы они менялись по своим правилам, а не кто как захочет. Проще говоря, это посредники, которые смотрят, можно что-то сделать с данными или нет. Если можно — делают, если нельзя — нет. В итоге и данные в безопасности, и у пользователя есть инструмент для работы с ними.
Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.