ES6 introduces classes for JavaScript, but for complex applications, they can be too simple. Class fields (also known as class attribute ) are designed to simplify constructors with private and static members. The proposal is currently in TC39 Phase 3: Candidate Stage and will likely be added to ES2019 (ES10). Node.js 12, Chrome 74, and Babel currently support private fields. Before we understand how class fields are implemented, it is useful to review the ES6 class. This article was updated in 2020. For more in-depth JavaScript knowledge, read our book "JavaScript: From Newbie to Ninja, Second Edition".
Key Points
ES6 category basics
Developers from languages such as C, C#, Java, and PHP may be confused by the object-oriented inheritance model of JavaScript. Therefore, ES6 introduced the class . They are mostly syntactic sugar, but offer a more familiar concept of object-oriented programming. A class is an object template that defines how objects of that type behave. The following Animal class defines general animals (classes are usually represented in initial capital letters to distinguish them from objects and other types):
class Animal { constructor(name = 'anonymous', legs = 4, noise = 'nothing') { this.type = 'animal'; this.name = name; this.legs = legs; this.noise = noise; } speak() { console.log(`${this.name} says "${this.noise}"`); } walk() { console.log(`${this.name} walks on ${this.legs} legs`); } }
Class declarations are always executed in strict mode. No need to add 'use strict'. Constructor method runs when creating an object of type Animal. It usually sets initial properties and handles other initializations. speak() and walk() are instance methods that add more functionality. You can now use the new keyword to create objects from this class:
let rex = new Animal('Rex', 4, 'woof'); rex.speak(); // Rex says "woof" rex.noise = 'growl'; rex.speak(); // Rex says "growl"
Getter and Setter
Setter is a special method used only to define values. Similarly, Getter is a special method for return values only. For example:
class Animal { constructor(name = 'anonymous', legs = 4, noise = 'nothing') { this.type = 'animal'; this.name = name; this.legs = legs; this.noise = noise; } speak() { console.log(`${this.name} says "${this.noise}"`); } walk() { console.log(`${this.name} walks on ${this.legs} legs`); } // setter set eats(food) { this.food = food; } // getter get dinner() { return `${this.name} eats ${this.food || 'nothing'} for dinner.`; } } let rex = new Animal('Rex', 4, 'woof'); rex.eats = 'anything'; console.log( rex.dinner ); // Rex eats anything for dinner.
Subclass or subclass
It is usually possible to use one class as the base class for another. The Human class can inherit all properties and methods in the Animal class using the extends keyword. Properties and methods can be added, removed, or changed as needed to create human objects easier and clearer:
class Animal { constructor(name = 'anonymous', legs = 4, noise = 'nothing') { this.type = 'animal'; this.name = name; this.legs = legs; this.noise = noise; } speak() { console.log(`${this.name} says "${this.noise}"`); } walk() { console.log(`${this.name} walks on ${this.legs} legs`); } }
super refers to the parent class, so it is usually the first call called in the constructor. In this example, the Human speak() method overrides the method defined in Animal. Now you can create an instance of Human object:
let rex = new Animal('Rex', 4, 'woof'); rex.speak(); // Rex says "woof" rex.noise = 'growl'; rex.speak(); // Rex says "growl"
Static methods and properties
Defining methods using static keywords allows it to be called on a class without creating an object instance. Consider Math.PI constants: There is no need to create a Math object before accessing PI properties. ES6 does not support the same static properties as other languages, but properties can be added to the class definition itself. For example, the Human class can be adapted to keep counts of how many human objects have been created:
class Animal { constructor(name = 'anonymous', legs = 4, noise = 'nothing') { this.type = 'animal'; this.name = name; this.legs = legs; this.noise = noise; } speak() { console.log(`${this.name} says "${this.noise}"`); } walk() { console.log(`${this.name} walks on ${this.legs} legs`); } // setter set eats(food) { this.food = food; } // getter get dinner() { return `${this.name} eats ${this.food || 'nothing'} for dinner.`; } } let rex = new Animal('Rex', 4, 'woof'); rex.eats = 'anything'; console.log( rex.dinner ); // Rex eats anything for dinner.
class will return the number of humans accordingly:
class Human extends Animal { constructor(name) { // 调用Animal构造函数 super(name, 2, 'nothing of interest'); this.type = 'human'; } // 重写Animal.speak speak(to) { super.speak(); if (to) console.log(`to ${to}`); } }
ES2019 Class Fields (New)
New class field implementation allows the initialization of public properties outside of any constructor at the top of the class:
let don = new Human('Don'); don.speak('anyone'); // Don says "nothing of interest" to anyone don.eats = 'burgers'; console.log( don.dinner ); // Don eats burgers for dinner.
This is equivalent to:
class Human extends Animal { constructor(name) { // 调用Animal构造函数 super(name, 2, 'nothing of interest'); this.type = 'human'; // 更新Human对象的计数 Human.count++; } // 重写Animal.speak speak(to) { super.speak(); if (to) console.log(`to ${to}`); } // 返回人类对象的个数 static get COUNT() { return Human.count; } } // 类的静态属性本身 - 不是其对象 Human.count = 0;
If you still need the constructor, the initializer will be executed before it runs.
In the example above, static properties are added to the class definition object in an inelegant way after defining the class object. You don't need to use class fields:
console.log(`Humans defined: ${Human.COUNT}`); // Humans defined: 0 let don = new Human('Don'); console.log(`Humans defined: ${Human.COUNT}`); // Humans defined: 1 let kim = new Human('Kim'); console.log(`Humans defined: ${Human.COUNT}`); // Humans defined: 2
This is equivalent to:
class MyClass { a = 1; b = 2; c = 3; }
ES6 class are public by default and can be checked or modified outside the class. In the Animal example above, nothing can prevent changing the food property without calling the eats setter:
class MyClass { constructor() { this.a = 1; this.b = 2; this.c = 3; } }
class MyClass { x = 1; y = 2; static z = 3; } console.log( MyClass.z ); // 3
class MyClass { constructor() { this.x = 1; this.y = 2; } } MyClass.z = 3; console.log( MyClass.z ); // 3
Benefit immediately: More concise React code!
React components usually have methods that are bound to DOM events. To ensure this resolves to a component, it is necessary to bind each method accordingly. For example:
class Animal { constructor(name = 'anonymous', legs = 4, noise = 'nothing') { this.type = 'animal'; this.name = name; this.legs = legs; this.noise = noise; } set eats(food) { this.food = food; } get dinner() { return `${this.name} eats ${this.food || 'nothing'} for dinner.`; } } let rex = new Animal('Rex', 4, 'woof'); rex.eats = 'anything'; // 标准setter rex.food = 'tofu'; // 完全绕过eats setter console.log( rex.dinner ); // Rex eats tofu for dinner.
class MyClass { a = 1; // .a是公共的 #b = 2; // .#b是私有的 static #c = 3; // .#c是私有的和静态的 incB() { this.#b++; } } let m = new MyClass(); m.incB(); // 运行正常 m.#b = 0; // 错误 - 私有属性不能在类外部修改
Class field: Improved?
The definition of ES6 class is too simple. ES2019 class fields require less code, improve readability, and implement some interesting possibilities for object-oriented programming. Using # means privateness has received some criticism, mainly because it is ugly and feels like a skill. Most languages implement the private keyword, so trying to use that member outside the class will be rejected by the compiler. JavaScript is interpreted. Consider the following code:
class Animal { constructor(name = 'anonymous', legs = 4, noise = 'nothing') { this.type = 'animal'; this.name = name; this.legs = legs; this.noise = noise; } speak() { console.log(`${this.name} says "${this.noise}"`); } walk() { console.log(`${this.name} walks on ${this.legs} legs`); } }
This will throw a runtime error on the last line, but it is just a serious consequence of trying to set the property. JavaScript is deliberately tolerant, and ES5 allows modifying properties on any object. Although clumsy, the # symbol is invalid outside the class definition. Trying to access myObject.#secret may throw a syntax error. This debate will continue, but class fields are already adopted in multiple JavaScript engines, like it or not. They will continue to exist.
FAQs (FAQs) about JavaScript Private Class Fields
Private class fields in JavaScript provide a way to encapsulate or hide data in a class, which is the basic principle of object-oriented programming. This encapsulation ensures that the internal state of an object can only be changed by a class explicitly defined way. This makes the code more robust and predictable because it prevents external code from accidentally changing the state of the object in an unexpected way. Additionally, private fields can help simplify the interface of classes because they reduce the number of properties and methods exposed to the outside world.
In JavaScript, private class fields are declared by adding a hash (#) symbol before the field name. For example, to declare a private field named "value" in a class, you can write a #value. This field can then be accessed only in the inner methods of the class, not from outside the class.
No, private class fields in JavaScript cannot be accessed from outside the class. This is by design, because one of the main uses of private fields is to hide internal data from the outside world. If you try to access a private field from outside the class, JavaScript will throw a syntax error.
Yes, JavaScript classes can have both private and public fields. Public fields are declared the same way as private fields, but have no hash (#) prefix. Unlike private fields that can only be accessed from inside a class, public fields can be accessed and modified from inside and outside the class.
Private class fields and private methods in JavaScript have similar uses, both of which provide a way to hide internal details of a class from the outside world. However, they are used differently. Private fields are used to store data that can only be accessed inside the class, while private methods are functions that can only be called inside the class.
Private class fields are relatively new features in JavaScript, so not all environments support it. At the time of writing, the latest versions of most major browsers, including Chrome, Firefox, and Safari, support private fields. However, Internet Explorer does not support them. If you need to write code that runs in all browsers, you may need to use a converter like Babel to convert the code into a form that older browsers can understand.
To use a private class field in an internal method of a class, simply refer to the field with its name (prefixed with a hash (#) symbol). For example, if you have a private field called "value", you can access it in your method like this: this.#value.
Yes, private class fields can be used in subclasses of JavaScript. However, each subclass has its own independent set of private fields that are not shared with superclasses or other subclasses. This means that if the private field declared by the subclass is of the same name as the private field in the superclass, the two fields are completely independent and do not interfere with each other.
No, private class fields in JavaScript cannot be used in static methods. This is because static methods are associated with the class itself, not with instances of the class, and private fields are accessible only in instances of the class.
No, private class fields in JavaScript are not included in the object's property iteration. This is by design, because one of the main uses of private fields is to hide internal data from the outside world. If you need to iterate over the properties of the object, you should use a public field or method instead.
This response maintains the original image format and placement, and paraphrases the text while preserving the original meaning. The code examples remain largely unchanged as significant alteration would change the meaning.
The above is the detailed content of JavaScript's New Private Class Fields, and How to Use Them. For more information, please follow other related articles on the PHP Chinese website!