Одинаковое имя свойства и гетта, сеттера у класса в javascript
'use strict';
class UserService {
username;
password;
constructor(username, password) {
this.password = password;
this.username = username;
}
get password() {
return `getter ${this.password}`;
}
set password(v) {
this.password = '000';
}
}
const admin = new UserService('Fooman', '12345');
admin.password = '567890';
console.log('Username:', admin.username);
console.log('Password:', admin.password);
Почему можно указать геттер\сеттер и свойство с одинаковым именем. Причем геттер\сеттер не отрабатывают. Есть предположение, что метод записывается в прототип, а свойства перезаписываются при создании объекта.
Ответы (3 шт):
Считайте, что Вам повезло. Представьте, что работал бы геттер:
'use strict';
class UserService {
//username;
//password;
constructor(username, password) {
this.password = password;
this.username = username;
}
get password() {
return `getter ${this.password}`;
}
set password(v) {
this.password = '000';
}
}
const admin = new UserService('Fooman', '12345');
admin.password = '567890';
console.log('Username:', admin.username);
console.log('Password:', admin.password);
Геттеры и сеттеры, как и любые другие функции - добавляются в прототип объекта, в то время как поля добавляются непосредственно в объекте.
Таким образом поля и геттеры/сеттеры никак не пересекаются и до геттеров/сеттеров просто не доходит выполнение, так как идет обращение напрямую к полю.
При этом к ним можно все еще обратиться - получив их из прототипа.
Для свойств нужно воспользоваться функцией Object.getOwnPropertyDescriptor, чтобы получить объект содержащий описание нужного свойства, и у полученного объекта вызвать метод .get, передав ему в качестве контекста нужный объект:
'use strict';
class UserService {
username;
password;
constructor(username, password) {
this.password = password;
this.username = username;
}
get password() {
return `getter ${this.password}`;
}
set password(v) {
this.password = '000';
}
}
const admin = new UserService('Fooman', '12345');
admin.password = '567890';
console.log('Username:', admin.username);
console.log('Password:', admin.password);
console.log('getter:', Object.getOwnPropertyDescriptor(Object.getPrototypeOf(admin), 'password').get.call(admin))
Когда мне нужно иметь в классе геттеры и сеттеры, и при этом нужно еще хранить какое-то значение помимо геттера и сеттера, я использую приватные свойства с # в начале имени.
Напрямую к таким свойствам обратиться нельзя (только через геттеры/сеттеры).
'use strict';
class UserService {
// Приватные свойства класса должны быть перечислены в классе
// в обязательном порядке
#username;
// Можно даже указыват начальные значения по умолчанию
#password = [...crypto.getRandomValues(new Uint8Array(10))]
.map(byte => byte.toString(16).padStart(2,0)).join``;
constructor(data) {
if(data) {
// методы внутри класса могут обращаться к полям напрямую
if(data.username) this.#username = data.username;
// а могут через геттеры и сеттеры
if(data.password) this.password = data.password;
}
// Но вообще как правило, в конструкторе я делаю вот так:
// Object.assign(this, data);
}
get username(){
return this.#username || 'anonymous';
}
get password() {
return `getter ${this.#password}`;
}
set password(value) {
this.#password = `${value} setter`;
}
}
const admin = new UserService(
{username:'Fooman', password:'12345'}
);
console.log('Username:', admin.username);
console.log('Old Password:', admin.password);
// Снаружи класса можно обращаться только через геттеры и сеттеры
admin.password = '567890';
// Эта инструкция снаружи класса приведет к синтаксической ошибке:
// console.log(admin.#password);
console.log('New Password:', admin.password);
let test = new UserService();
console.log('Username:', test.username);
console.log('Password:', test.password);