Инкапсуляция является одним из ключевых понятий объектно-ориентированного программирования и представляет сокрытие состояния объекта от прямого доступа извне для поддержания целостности данных. По умолчанию все свойства объектов являются публичными, общедоступными, и мы к ним можем обратиться из любого места программы.
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 соответственно. Правда, в контексте функций-конструкторов они не имеют большого смысла, поэтому будут рассмотрены дальше.