Technologieaustausch

Zusammenfassung der ES6-Klasse (9)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Die Klasse in ES6 ist ein syntaktischer Zucker für die objektorientierte Programmierung und bietet eine prägnante Möglichkeit, die Struktur und das Verhalten von Objekten zu definieren.

In der JavaScript-Sprache erfolgt die Generierung von Instanzobjekten traditionell über Konstruktoren. Unten finden Sie ein Beispiel.

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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Grundsätzlich kann die ES6-Klasse nur als syntaktischer Zucker betrachtet werden. Die meisten ihrer Funktionen können durch die neue Klassenschreibmethode nur klarer gemacht werden und ähneln eher der Syntax der objektorientierten Programmierung. Der obige Code wird mithilfe von ES6-Klassen wie folgt umgeschrieben:

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

ES6-Klassen können als eine andere Möglichkeit angesehen werden, Konstruktoren zu schreiben:

class Point {
  // ...
}
typeof Point // "function"
Point === Point.prototype.constructor // true

----------------------------------------------------------------------------
class Point {
  constructor() {
    // ...
  }
  toString() {
    // ...
  }
  toValue() {
    // ...
  }
}
// 等同于
Point.prototype = {
  constructor() {},
  toString() {},
  toValue() {},
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

Haupteigenschaften:

1. Deklarative Syntax: Verwenden Sie das Schlüsselwort class, um eine Klasse zu deklarieren.
2. Konstrukteur: Verwenden Sie die Konstruktormethode, um eine Klasseninstanz zu initialisieren.
3. Instanzmethoden: Eine allgemeine Methode, die innerhalb einer Klasse definiert ist. Verwenden Sie diese, um auf Instanzeigenschaften zuzugreifen.
4. Statische Methoden: Wird mit dem Schlüsselwort static definiert und hängt nicht von der Instanz der Klasse ab.
5. Instanzeigenschaften: Im Konstruktor initialisieren oder Felddeklarationssyntax verwenden (derzeit ein Vorschlag der Stufe 3).
6. Vererbung: Implementiert mit dem Schlüsselwort „extens“.
7. Super-Schlüsselwort: Rufen Sie den Konstruktor oder die Methode der übergeordneten Klasse im Konstruktor der Unterklasse auf.
8. Getter und Setter: Verwenden Sie get und set, um Zugriffsmethoden für Eigenschaften zu definieren.
9. Private Eigenschaften und Methoden: Verwenden Sie #, um private Eigenschaften und Methoden zu definieren (derzeit ein Vorschlag der Stufe 3).

1. Grundlegende Klassendefinition und Instanziierung

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

2. Statische Methoden und Eigenschaften

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3. Vererbung und 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

4. Getter und Setter

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

Hinweise zum Unterricht

(1) Strikter Modus

Intern befinden sich Klassen und Module standardmäßig im strikten Modus, daher ist es nicht erforderlich, den Ausführungsmodus mit „use strict“ anzugeben. Solange Ihr Code in einer Klasse oder einem Modul geschrieben ist, ist nur der strikte Modus verfügbar. Wenn man bedenkt, dass der gesamte zukünftige Code tatsächlich in Modulen ausgeführt wird, aktualisiert ES6 tatsächlich die gesamte Sprache auf den strikten Modus.

(2) Es erfolgt keine Förderung

Klassen haben kein variables Heben (Hoist), was sich völlig von ES5 unterscheidet.

new Foo(); // ReferenceError
class Foo {}

//不会报错
//因为 Bar 继承 Foo 的时候, Foo 已经有定义了。
//但是,如果存在 class 的提升,上面代码就会报错,
//因为 class 会被提升到代码头部,而 let 命令是不提升的,
//所以导致 Bar 继承 Foo 的时候, Foo 还没有定义。
{
  let Foo = class {};
  class Bar extends Foo {
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

(3) Namensattribut

Da eine ES6-Klasse im Wesentlichen nur ein Wrapper für den ES5-Konstruktor ist, werden viele Funktionen der Funktion von der Klasse geerbt, einschließlich des Namensattributs.

class Point {}
Point.name // "Point"
//name 属性总是返回紧跟在 class 关键字后面的类名。
  • 1
  • 2
  • 3

(4)Generatormethode

Wenn einer Methode ein Sternchen (*) vorangestellt ist, bedeutet dies, dass es sich bei der Methode um eine Generatorfunktion handelt.

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 循环会自动调用这个遍历器。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

(5) Der Sinn davon

Wenn eine Klassenmethode dies enthält, zeigt sie standardmäßig auf eine Instanz der Klasse. Sie müssen jedoch sehr vorsichtig sein, da diese Methode bei alleiniger Verwendung zu Fehlern führen kann.

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Vermeiden Sie dies, binden Sie dies im Konstruktor:

class Logger {
  constructor() {
    this.printName = this.printName.bind(this);
  }
  // ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Vermeiden Sie dies, verwenden Sie Pfeilfunktionen:

class Obj {
  constructor() {
    this.getThis = () => this;
  }
}
const myObj = new Obj();
myObj.getThis() === myObj // true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Vermeiden Sie dies, verwenden Sie 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());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18