Private Accessors
Happy Halloween! I'm going to continue on with another ES2021 feature, called Private Accessors. This feature is similar and related to Private Class Methods.
Accessors
When we talk about Accessors, we're talking about Getters and Setters. A Getter allows you to retrieve the value of an object property, and a Setter allows you to define the value of an object property.
class User { constructor() { this.firstName = ""; this.lastName = ""; } get fullName() { return `${this.firstName} ${this.lastName}`; } set fullName(name) { [this.firstName, this.lastName] = name.split(" "); }}
const joey = new User();
In the code above we have defined a User
class. By default, a User
will have two properties, firstName
and lastName
, both initially equal to empty strings.
Below the User
class definition we are creating a new User
and setting it to the variable joey
.
Now we can use a Setter to assign values to the firstName
and lastName
properties on the joey
object. Here is our Setter method:
set fullName(name) { [this.firstName, this.lastName] = name.split(" ");}
The fullName
Setter accepts a name
parameter, which will be a first and last name, like "Joey Reyes". We use the .split()
method to create an array of this name, which looks like: ["Joey", "Reyes"]
. We then use Array Destructuring to set the first item in this array to be the value of the firstName
property and the second item in the array to be the value of the lastName
property.
We actually call this method like so:
joey.fullName = "Joey Reyes";
By assigning the value of the method with the =
equals sign, we are calling it as a Setter.
With the firstName
and lastName
property values defined by the Setter, we can now use the Getter function (of the same name, fullName
) to retrieve those values:
joey.fullName;// Expected result: "Joey Reyes"
We can also directly call the firstName
and lastName
properties to get their individual values:
joey.firstName;// Expected result: "Joey"joey.lastName;// Expected result: "Reyes"
Private Accessors
Now that we've reviewed what good, old fashioned Accessors are, let's look at Private Accessors, which are Getters and Setters that run privately and work with private values.
class User { #password;
constructor() { this.firstName = ""; this.lastName = ""; } get fullName() { return `${this.firstName} ${this.lastName}`; } set fullName(name) { [this.firstName, this.lastName] = name.split(" "); this.#generatedPassword = `${this.firstName.toLowerCase()}123`; console.log(this.#generatedPassword); } get #generatedPassword() { return `🔐 ${this.#password} 🔐`; } set #generatedPassword(password) { this.#password = password; }}
const joey = new User();
joey.fullName = "Joey Reyes";
The code above has added several things onto the first code example. We have added a private field called #password
, which will store a password that we generate.
Like with Private Class Methods, Private Fields and Private Accessors (Getters and Setters) use a #
hash character to make those fields or accessors private.
Here is our new Private Setter:
set #generatedPassword(password) { this.#password = password;}
This Private Setter accepts a parameter, password
, and sets the value of that passed argument to be the value of the #password
private field.
We also have a new Private Getter:
get #generatedPassword() { return `🔐 ${this.#password} 🔐`;}
This Private Getter simply returns the value of the #password
private field, and returns it with some lock and key emojis.
Lastly, we are actually calling the new Private Getter and Setter methods within the public fullName
Setter function:
set fullName(name) { [this.firstName, this.lastName] = name.split(" "); this.#generatedPassword = `${this.firstName.toLowerCase()}123`; console.log(this.#generatedPassword);}
After destructuring the firstName
and lastName
properties, we create a new password value by setting the value of firstName
to lowercase and appending it with the number 123
. This then uses the #generatedPassword
Setter to define this name/number string as the value of #password
. We then use the Getter #generatedPassword
within a console.log()
statement, which gives us the string: 🔐 joey123 🔐
.
So why do all of this? Well, say we run the following code:
class User { #password;
constructor() { this.firstName = ""; this.lastName = ""; } get fullName() { return `${this.firstName} ${this.lastName}`; } set fullName(name) { [this.firstName, this.lastName] = name.split(" "); this.#generatedPassword = `${this.firstName.toLowerCase()}123`; console.log(this.#generatedPassword); } get #generatedPassword() { return `🔐 ${this.#password} 🔐`; } set #generatedPassword(password) { this.#password = password; }}
const joey = new User();
joey.fullName = "Joey Reyes";joey.#generatedPassword;// Expected result: SyntaxError
If we try to call the #generatedPassword
Private Getter in the same manner as the fullName
Public Getter, we get a Synax Error because it's Private Accessor. We cannot call any of the Private functionality outside the scope of the class itself. This means that that data and functionality is protected.
From MDN: Class fields are public by default, but private class members can be created by using a hash #
prefix. The privacy encapsulation of these class features is enforced by JavaScript itself.
See more examples and documentation here.