Class Fields and Privacy
Declaring Fields
In languages such as Java and C++, you can declare and initialize variables, also known as fields or attributes, within the class body.
In JavaScript, the most common way to declare fields is within the class constructor:
class Account {
constructor() {
this.balance = 0;
}
}
const acc = new Account();
console.log(acc); // {"balance":0}
This is useful when you want to let the client create an object with its own values for the fields:
class Account {
constructor(balance) {
this.balance = balance;
}
}
const acc = new Account(10);
console.log(acc); // {"balance":10}
Alternatively, you can initialize the fields in the class body:
class Account {
balance = 0;
constructor(name) {
this.name = name;
}
}
const acc1 = new Account("Jim");
const acc2 = new Account("John");
console.log(acc1); // {"balance":0,"name":"Jim"}
console.log(acc2); // {"balance":0,"name":"John"}
It is easier to read if you always initialize your class fields in the constructor, so that is what we recommend.
Fields with Default Values
You can initialize a field and use the constructor to override its initial value. Here is an example:
class Account {
balance = 0;
constructor(balance) {
if (balance) this.balance = balance;
}
}
const acc1 = new Account();
const acc2 = new Account(10);
console.log(acc1); // {"balance":0}
console.log(acc2); // {"balance":10}
You can also use parameters with default values to achieve the same result:
class Account {
constructor(balance = 0) {
this.balance = balance;
}
}
const acc1 = new Account();
const acc2 = new Account(10);
console.log(acc1); // {"balance":0}
console.log(acc2); // {"balance":10}
Declaring Fields Inside Methods
You are not limited to the constructor or the class body. You can declare a field in any method.
class Publication {
setTitle(title) {
this.title = title;
}
setAuthor(author) {
this.author = author;
}
getTitle() {
return this.title;
}
getAuthor() {
return this.author;
}
print() {
console.log(this.getTitle() + " by " + this.getAuthor());
}
}
const publication = new Publication();
publication.setTitle("CS280 Notes");
publication.setAuthor("Ali Madooei");
publication.print(); // CS280 Notes by Ali Madooei
You can assign properties in any method, but we do not recommend it. The set of fields an object has then depends on which methods have been called on it, and that makes the code harder to understand.
Information Hiding
Private fields can be declared using a hash # prefix. They can only be accessed from within the class that defines them:
class Account {
#balance = 0;
deposit(amount) {
this.#balance += amount;
}
print() {
console.log(this.#balance);
}
}
const acc = new Account();
acc.deposit(10);
console.log(acc); // {}
acc.print(); // 10
Here, #balance is a private field. If you try to access #balance outside of the class methods, you get a syntax error. That is what encapsulation means: the internal details of the class are hidden from the code outside it.
Declaring Methods
Methods can be declared in the class body or within the constructor. Here is an example of declaring a method in the class body:
class Account {
balance = 0;
deposit(amount) {
this.balance += amount;
}
withdraw(amount) {
this.balance -= amount;
}
print() {
console.log(this.balance);
}
}
In this example, deposit, withdraw, and print are methods of the Account class. They can be invoked on an instance of the Account class:
const acc = new Account();
acc.deposit(10);
acc.withdraw(5);
acc.print(); // 5
You can also declare methods within the constructor:
class Account {
constructor() {
this.balance = 0;
this.deposit = function (amount) {
this.balance += amount;
};
this.withdraw = function (amount) {
this.balance -= amount;
};
this.print = function () {
console.log(this.balance);
};
}
}
In this example, deposit, withdraw, and print are declared within the constructor. They can be invoked in the same way as the previous example. In a situation like this, you can use closures to create private methods or fields. Here is an example where balance is a private field:
class Account {
constructor() {
let balance = 0;
this.deposit = function (amount) {
balance += amount;
};
this.withdraw = function (amount) {
balance -= amount;
};
this.print = function () {
console.log(balance);
};
}
}
You can also use arrow functions to declare methods (inside the constructor or class body):
class Account {
constructor() {
this.balance = 0;
this.deposit = (amount) => {
this.balance += amount;
};
this.withdraw = (amount) => {
this.balance -= amount;
};
}
print = () => {
console.log(this.balance);
};
}
Methods can be declared in the class body or in the constructor. We recommend the class body, because it is easier to read and to maintain. You can also make any method private with the # prefix. The method can then only be called from within the class that defines it.