What are the restrictions on using getters and setters in javascript? For example, here are a few scenarios I've seen when just doing trial-and-error:
class User {
// 1 - must have an alias somewhere or will get loop
constructor(name) {
this.name = name;
}
get name() {
console.log('--- Getter ---');
return this.name;
}
set name(name) {
console.log('--- Setter --- ');
this.name = name;
}
}
const user = new User('David');
console.log(user.name);
class User {
name;
// 2 - setter/getter must have a property with exact name in constructor?
constructor(name) {
this._name = name;
}
get name() {
console.log('--- Getter ---');
return this._name;
}
set name(name) {
console.log('--- Setter --- ');
this._name = name;
}
}
const user = new User('David');
console.log(user.name);
user.name = 'Keith';
console.log(user.name);
Is a correct understanding of a setter/getter that:
Finally, putting it all togther, does the following seem like a good pattern to hide fields when user a getter/setter, as it seems like #name (private) and name (public) act like two different variables.
class User {
#name;
constructor(name) {
this.name = name;
}
get name() {
console.log('-getter-');
return this.#name;
}
set name(name) {
console.log('-setter-');
this.#name = name
}
}
bob = new User('Bob');
bob.name = 'Bobby';
console.log(bob.name);
A backing field is not a requirement, needless to say a backing field with the same name. You don't even need setter and getter if all you do is just setting and getting a backing field, since there would be functionally no difference than a normal field.
Getter and Setter are usually used when
Example for case 1:
class Foo
{
constructor(bar)
{
this.bar = bar;
}
get barSquare()
{
return this.bar * this.bar;
}
set barSquare(x)
{
this.bar = Math.sqrt(x);
}
}
let foo = new Foo(4);
console.log(foo.barSquare);
foo.barSquare = 25;
console.log(foo.bar);
Example for case 2:
You do need a backing field in this case, though the name of the backing field can be anything except the setter/getter name.
class Foo
{
constructor(bar)
{
this._bar = bar;
}
get bar()
{
return this._bar;
}
set bar(x)
{
console.log(`bar is changed to ${x}!`);
this._bar = x;
}
}
let foo = new Foo(4);
console.log(foo.bar);
foo.bar = 5;
console.log(foo.bar);
Finally, the parameter name (bar) defined in constructor(bar) is totally unrelated. It can be any legal variable name. It is scoped to the constructor block. For example, it can be
class Foo
{
constructor(totallyRandomName)
{
this.someBackingFieldName = totallyRandomName;
}
get bar()
{
return this.someBackingFieldName;
}
set bar(x)
{
console.log(`bar is changed to ${x}!`);
this.someBackingFieldName = x;
}
}
let foo = new Foo(4);
console.log(foo.bar);
foo.bar = 5;
console.log(foo.bar);
Giving a stab at the comments from @Bergi:
[ From question, incorrect assumption that] "The setter/getter must have that exact name defined in the constructor."
class Person {
name;
set name(y) {
console.log('setName');
this.name = y;
}
get name() {
console.log('getName');
return this.name;
}
}
let bob = new Person();
bob.name = 'Bob'
console.log(bob.name);
._name directly.class Person {
constructor(x) {
this.someOtherName = x;
}
set name(y) {
console.log('setName');
this.someOtherName = y;
}
get name() {
console.log('getName');
return this.someOtherName;
}
}
let bob = new Person();
bob.name = 'Bob'
console.log(bob.name);