I know that using an underscore is just a convention to define private variables in JavaScript. But I came across a use case [while using a class] where use of _ seems mandatory to make the code work! My question is how _ is used under the hood by get and set.
The below code throws an error:
RangeError: Maximum call stack size exceeded
class User {
  constructor(name) {
    this.name = name;
  }
  get name() {
    return this.name;
  }
  set name(val) {
    this.name = val;
  }
}
let user = new User("Jhon");
console.log(user.name);
Now, if I use _ the code works!
class User {
  constructor(name) {
    this.name = name;
  }
  get name() {
    return this._name; // Added "_" here
  }
  set name(val) {
    this._name = val; // Added "_" here
  }
}
let user = new User("Jhon");
console.log(user.name);
Your first snippet uses the same name for the getter/setter as the property you try to assign to. So, in the constructor, when you do
this.name = name;
you are invoking the name setter, which does:
this.name = val;
again invoking the name setter, which recursively calls itself until the stack overflows.
Using a different variable name for the actual property the data is stored in (compared to the getters/setters) allows for the code to work as intended. It doesn't have to be prefixed with an underscore - pretty much anything other than the same name used by the getters/setters will work.
class User {
  constructor(name) {
    this.name = name;
  }
  get name() {
    return this.actualProperty;
  }
  set name(val) {
    this.actualProperty = val;
  }
}
let user = new User("Jhon");
console.log(user.name);
The _ before a property name is generally meant to indicate that the property is meant to be private, and that only the class itself should access it, but it's no guarantee - users of the class are still free to reference user._name if they wish. If you want actual private data for each instance, you should define the class in a closure with a WeakMap that holds the private data:
const User = (() => {
  const data = new WeakMap();
  return class User {
    constructor(name) {
      this.name = name;
    }
    get name() {
      return data.get(this);
    }
    set name(val) {
      data.set(this, val);
    }
  }
})();
let user = new User("Jhon");
console.log(user.name);
Just look at this piece of code logically:
get name() {
    return this.name
}
You read object.name. To return a value, the get name() getter reads this.name, which, in turn, resolves to get name(). And now, welcome to the infinite loop.
Hence, you need a separate variable name (to store the actual content of name) than the getter's name. That would be a private variable, and it has become a convention to prepend an underscore in these cases.
The _ affix is commonly used for private properties.
You use private properties in addition to getters and/or setters when you want to be able to control how and when you can update a property, or add side effects to those actions.
You should also have a private property declaration in your class
class User {
  private _name; // <-- here
  constructor(name) {
    this.name = name;
  }
  get name() {
    return this._name;
  }
  set name(val) {
    this._name = val;
  }
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With