Fields
As we talked about in the introduction to classes, they can be considered as boxes or containers for data and functionality. The functionality is covered by class methods, which we'll talk about in one of the next articles, while the data part is taken care of by class fields.
We already used a field in the introduction to classes example in the previous article, but in this article I want to go back and start from the beginning, giving you an introduction to fields and discussing it in detail.
A class field is basically just a variable, contained by the class, but it does offer some extra functionality, as we'll see in some of the later examples.
Simple fields
In its most simple form, a class field is added to a class simply by writing its name inside of the class body, followed by a semicolon. Let's illustrate that with a Dog class with two fields:
class Dog
{
name;
age;
}
This creates a class called Dog, containing two fields: "name" and "age".
But perhaps you would like to give your fields an initial value - no problem, you can do that, just like with regular variables:
class Dog
{
name = "Dog Doe";
age = 7;
}
Using the fields
By default, a class field in JavaScript is public, which means that it can be accessed from both inside and outside of the class. We'll talk more about class member visibility later on, but for now, let's try using the fields in a more complete example:
class Dog
{
name = "Dog Doe";
age = 7;
Describe()
{
return this.name + " is " + this.age + " years old";
}
}
let dog = new Dog();
alert(dog.Describe());
// Dog birthday...
dog.age = dog.age + 1;
alert(dog.Describe());
As you can see, after creating the dog object and calling the Describe() method, I then access the age field and add one to the age. To establish that the age has changed, I call the Describe() method again. We now use the field from within the class (in the Describe() method) as well as from the outside.
Private fields
However, sometimes you want to keep access to a field strictly to within the class. This is possible with JavaScript by defining the field as private, and as a concept it's often referred to as encapsulation because you are hiding something internally from the consumer of the class, allowing only the class itself to manipulate the data.
This might sound a bit strange, because you as the programmer are often both the definer and the consumer of the class, as we have just seen in the previous examples, but you have to think a bit bigger here. One example is a large project with hundreds or even thousands of classes, created by multiple developers. In a situation like that, it's important for the creator of the class to have strict control over which members are exposed to the consumer of the class, which could easily be another programmer.
In JavaScript, a field is marked as private by prefixing it with the number/hash sign (#). When doing so, the field can no longer be accessed from outside the class, but still from within the class, as we'll see in this modified version of our Dog class example:
class Dog
{
#name = "Dog Doe";
#age = 7;
Describe()
{
return this.#name + " is " + this.#age + " years old";
}
}
let dog = new Dog();
alert(dog.Describe());
// Dog birthday...
dog.#age = dog.#age + 1;
alert(dog.Describe());
Notice that I have now prefixed the field names with the number/hash sign (#name and #age). Also notice that the number/hash sign is not an operator or anything like that. It becomes a part of the name of the field, like any other character, but it has special meaning to the interpreter, marking it as private.
Now, if you try to run this example, you won't get far. Some JavaScript errors are only caught at runtime, but this error is discovered already when the interpreter analyzes the code, resulting in a syntax error. When your code contains syntax errors, it won't run at all, but you'll see an error in the log like this one:
Uncaught SyntaxError: Private field '#age' must be declared in an enclosing class
Now if you try running the example without the last couple of lines, it will run just fine:
class Dog
{
#name = "Dog Doe";
#age = 7;
Describe()
{
return this.#name + " is " + this.#age + " years old";
}
}
let dog = new Dog();
alert(dog.Describe());
We still access the fields, but only from within the class, which is still allowed for private fields. The class now has full control of the fields and you will have to use a public method, like the Describe() method to indirectly access the fields.
To gain even more control over a field, we can use something called getters and setters. These are special types of methods, so we'll get to them in a separate article, after we have discussed class methods in general.
Summary
Fields are like variables, but for classes. They can, by default, be changed from both inside as well as outside of the class, but you can change this behavior by marking them as private fields.