2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
The class in ES6 is a syntactic sugar for object-oriented programming, providing a concise way to define the structure and behavior of an object.
In JavaScript, the traditional way to generate instance objects is through constructors. Here is an example.
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
Basically, ES6 class can be regarded as a syntax sugar. Most of its functions can be achieved by ES5. The new class writing method just makes the object prototype writing method clearer and more like the syntax of object-oriented programming. The above code is rewritten with ES6 class, which is as follows:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
ES6 classes can be seen as another way to write constructors:
class Point {
// ...
}
typeof Point // "function"
Point === Point.prototype.constructor // true
----------------------------------------------------------------------------
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
1. Declarative syntax: Use the class keyword to declare a class.
2. Constructor: Use the constructor method to initialize a class instance.
3. Instance Methods: Ordinary methods defined within a class use this to access instance attributes.
4. Static Methods: Defined using the static keyword and does not depend on the instance of the class.
5. Instance Attributes: Initialize in the constructor, or use field declaration syntax (currently a Stage 3 proposal).
6. Inheritance: Implemented using the extends keyword.
7. super keyword: Call the constructor or method of the parent class in the constructor of the subclass.
8. Getters and setters: Use get and set to define property accessors.
9. Private properties and methods: Use # to define private properties and methods (currently a Stage 3 proposal).
1. Basic class definition and instantiation
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return `Point(${this.x}, ${this.y})`;
}
}
let point = new Point(10, 20);
console.log(point.toString()); // 输出: Point(10, 20)
2. Static methods and properties
class MathUtils {
constructor() {
console.log(MyClass.myStaticProp); // 42
}
static add(a, b) {
return a + b;
}
static myStaticProp = 42;
}
console.log(MathUtils.add(1, 2)); // 输出: 3
3. Inheritance and super
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
area() {
return this.width * this.height;
}
}
class Square extends Rectangle {
constructor(sideLength) {
super(sideLength, sideLength);
}
}
let square = new Square(5);
console.log(square.area()); // 输出: 25
4. Getters and setters
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
get area() {
return this.width * this.height;
}
set width(newWidth) {
if (newWidth > 0) {
this.width = newWidth;
} else {
console.log("Width must be positive.");
}
}
}
let rect = new Rectangle(4, 5);
console.log(rect.area); // 输出: 20
rect.width = -10; // 输出: Width must be positive.
(1) Strict mode
The default mode is strict inside classes and modules, so there is no need to specify the mode with use strict. As long as your code is written in a class or module, only strict mode is available. Considering that all future code will actually run in modules, ES6 actually upgrades the entire language to strict mode.
(2) No improvement
Classes do not have variable hoisting, which is completely different from ES5.
new Foo(); // ReferenceError
class Foo {}
//不会报错
//因为 Bar 继承 Foo 的时候, Foo 已经有定义了。
//但是,如果存在 class 的提升,上面代码就会报错,
//因为 class 会被提升到代码头部,而 let 命令是不提升的,
//所以导致 Bar 继承 Foo 的时候, Foo 还没有定义。
{
let Foo = class {};
class Bar extends Foo {
}
}
(3) name attribute
Since ES6 classes are essentially just a wrapper around ES5 constructors, many features of functions are inherited by Class, including the name property.
class Point {}
Point.name // "Point"
//name 属性总是返回紧跟在 class 关键字后面的类名。
(4) Generator method
If an asterisk ( * ) is placed before a method, it means that the method is a Generator function.
class Foo {
constructor(...args) {
this.args = args;
}
* [Symbol.iterator]() {
for (let arg of this.args) {
yield arg;
}
}
}
for (let x of new Foo('hello', 'world')) {
console.log(x);
}
// hello
// world
//Foo 类的 Symbol.iterator 方法前有一个星号,表示该方法是一个 Generator 函数。
//Symbol.iterator 方法返回一个 Foo 类的默认遍历器, for...of 循环会自动调用这个遍历器。
(5) The direction of this
If a class method contains this, it points to the instance of the class by default. However, you must be very careful, as it is likely to cause an error if the method is used alone.
class Logger {
printName(name = 'there') {
this.print(`Hello ${name}`);
}
print(text) {
console.log(text);
}
}
const logger = new Logger();
const { printName } = logger;
printName(); // TypeError: Cannot read property 'print' of undefined
Avoid using this and bind this in the constructor:
class Logger {
constructor() {
this.printName = this.printName.bind(this);
}
// ...
}
Avoid using this and use arrow functions:
class Obj {
constructor() {
this.getThis = () => this;
}
}
const myObj = new Obj();
myObj.getThis() === myObj // true
Avoid using this, use Proxy
function selfish (target) {
const cache = new WeakMap();
const handler = {
get (target, key) {
const value = Reflect.get(target, key);
if (typeof value !== 'function') {
return value;
}
if (!cache.has(value)) {
cache.set(value, value.bind(target));
}
return cache.get(value);
}
};
const proxy = new Proxy(target, handler);
return proxy;
}
const logger = selfish(new Logger());