Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do developers use "_" while using get and set in JavaScript? [duplicate]

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);
like image 494
Learner Avatar asked Aug 03 '19 09:08

Learner


3 Answers

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);
like image 161
CertainPerformance Avatar answered Oct 16 '22 20:10

CertainPerformance


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.

like image 4
fjc Avatar answered Oct 16 '22 20:10

fjc


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;
  }
}
like image 2
Morphyish Avatar answered Oct 16 '22 22:10

Morphyish