Инкапсуляция является одним из ключевых понятий объектно-ориентированного программирования и представляет сокрытие состояния объекта от прямого доступа извне для поддержания целостности данных. По умолчанию все свойства объектов являются публичными, общедоступными, и мы к ним можем обратиться из любого места программы.
function User(uName, uAge) { this.name = uName; this.age = uAge; this.print = function(){ console.log(`Name: ${this.name} Age: ${this.age}`); }; } const tom = new User("Tom", 39); tom.age = 11500; tom.print(); // Name: Tom Age: 11500
Однако подобный способ доступа может быть нежелателен. Так, в примере выше свойству age, которое представляет возраст, мы можем присвоить самые разные, в том числе и недопустимые значения.
Но мы можем их скрыть от доступа извне. Для этого свойство определяется как локальная переменная/константа:
function User(uName, uAge) { this.name = uName; let _age = uAge; this.print = function(){ console.log(`Name: ${this.name} Age: ${_age}`); }; } const tom = new User("Tom", 39); tom._age = 11500; tom.print(); // Name: Tom Age: 39
В конструкторе User объявляется локальная переменная _age
вместо свойства age
:
let _age = uAge;
Как правило, названия локальных переменных в конструкторах начинаются со знака подчеркивания. Причем такая переменная также может получать данные из параметров конструктора, и ее можно использовать в функциях внутри конструктора. Однако обратиться извне к ней не получится:
tom._age = 11500;
Здесь для объекта tom определяется новое свойство, которое называется, как и переменная _age. Но это свойство _age не окажет никакого влияния на локальную переменную _age, что мы можем увидеть по консольному выводу метода print.
Выше мы скрыли от доступа извне значение возраста в локальную переменную _age, однако иногда все таки требуется некоторый доступ, например, для того же консольного вывода или изменения. В этом случае мы можем определить специальные методы доступа - геттер (для получения значения) и сеттер (для изменения значения).
function User(uName, uAge) { this.name = uName; let _age = uAge; // геттер - возвращаем значение переменной this.getAge = function() { return _age; } // устанавливаем значение переменной this.setAge = function(age) { if(age >0 && age<110){ // если возраст больше 0 и меньше 110 _age = age; } else { console.log("Недопустимое значение"); } } this.print = function(){ console.log(`Name: ${this.name} Age: ${_age}`); }; } const tom = new User("Tom", 39); // получаем значение console.log(tom.getAge()) // 39 // устанавливаем новое значение tom.setAge(22); console.log(tom.getAge()) // 22 tom.setAge(11500); // Недопустимое значение console.log(tom.getAge()) // 22
Для того, чтобы работать с возрастом пользователя извне, определяются два метода. Метод getAge()
предназначен для получения значения переменной
_age. Этот метод еще называется геттер (getter). Второй метод - setAge
, который еще называется сеттер (setter), предназначен для установки
значения переменной _age.
Плюсом такого подхода является то, что мы имеем больший контроль над доступом к значению _age. Например, мы можем проверить какие-то сопутствующие условия, как в данном случае проверяются тип значение (он должен представлять число), само значение (возраст не может быть меньше 0).
Стоит отметить, что JavaScript также предоставляет специальные конструкции для создания геттеров и сеттеров - get и set соответственно. Правда, в контексте функций-конструкторов они не имеют большого смысла, поэтому будут рассмотрены дальше.