Die neue class
Syntax ist, für jetzt , meist syntaktischen Zucker. (Aber Sie wissen, die gute Art von Zucker.) In ES2015-ES2019 class
gibt es nichts, was Sie mit Konstruktorfunktionen und Reflect.construct
(einschließlich Unterklassen Error
und Array
¹) nicht tun können . ( In ES2021 gibt es wahrscheinlich einige Dinge, die Sie damit tun können class
, die Sie sonst nicht tun können: private Felder , private Methoden und statische Felder / private statische Methoden .)
Ist es außerdem class
eine andere Art von OOP oder immer noch die prototypische Vererbung von JavaScript?
Es ist dieselbe prototypische Vererbung, die wir immer hatten, nur mit einer saubereren und bequemeren Syntax, wenn Sie Konstruktorfunktionen ( new Foo
usw.) verwenden möchten. (Besonders im Fall der Ableitung von Array
oder Error
, was Sie in ES5 und früher nicht konnten. Sie können jetzt mit Reflect.construct
[ spec , MDN ], aber nicht mit dem alten ES5-Stil.)
Kann ich es mit ändern .prototype
?
Ja, Sie können das prototype
Objekt im Konstruktor der Klasse weiterhin ändern, nachdem Sie die Klasse erstellt haben. ZB ist das völlig legal:
class Foo {
constructor(name) {
this.name = name;
}
test1() {
console.log("test1: name = " + this.name);
}
}
Foo.prototype.test2 = function() {
console.log("test2: name = " + this.name);
};
Gibt es Geschwindigkeitsvorteile?
Durch die Bereitstellung hierfür eine spezifische Idiom, nehme ich an, es ist möglich , dass der Motor in der Lage sein kann , eine bessere Optimierung des Jobs zu tun. Aber sie können schon schrecklich gut optimieren, ich würde keinen signifikanten Unterschied erwarten.
Welche Vorteile bietet die ES2015 (ES6) -Syntax class
?
Kurz gesagt: Wenn Sie Konstruktorfunktionen überhaupt nicht verwenden Object.create
, class
ist es für Sie nicht hilfreich , sie zu bevorzugen oder ähnlich zu sein.
Wenn Sie Konstruktorfunktionen verwenden, gibt es einige Vorteile für class
:
Die Syntax ist einfacher und weniger fehleranfällig.
Es ist viel einfacher (und wiederum weniger fehleranfällig), Vererbungshierarchien mit der neuen Syntax einzurichten als mit der alten.
class
schützt Sie vor dem häufigen Fehler, dass new
die Konstruktorfunktion nicht verwendet werden kann (indem der Konstruktor eine Ausnahme auslöst, wenn er this
kein gültiges Objekt für den Konstruktor ist).
Das Aufrufen der Version einer Methode des übergeordneten Prototyps ist mit der neuen Syntax viel einfacher als mit der alten ( super.method()
anstelle von ParentConstructor.prototype.method.call(this)
oder Object.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)
).
Hier ist ein Syntaxvergleich für eine Hierarchie:
// ***ES2015+**
class Person {
constructor(first, last) {
this.first = first;
this.last = last;
}
personMethod() {
// ...
}
}
class Employee extends Person {
constructor(first, last, position) {
super(first, last);
this.position = position;
}
employeeMethod() {
// ...
}
}
class Manager extends Employee {
constructor(first, last, position, department) {
super(first, last, position);
this.department = department;
}
personMethod() {
const result = super.personMethod();
// ...use `result` for something...
return result;
}
managerMethod() {
// ...
}
}
Beispiel:
// ***ES2015+**
class Person {
constructor(first, last) {
this.first = first;
this.last = last;
}
personMethod() {
return `Result from personMethod: this.first = ${this.first}, this.last = ${this.last}`;
}
}
class Employee extends Person {
constructor(first, last, position) {
super(first, last);
this.position = position;
}
personMethod() {
const result = super.personMethod();
return result + `, this.position = ${this.position}`;
}
employeeMethod() {
// ...
}
}
class Manager extends Employee {
constructor(first, last, position, department) {
super(first, last, position);
this.department = department;
}
personMethod() {
const result = super.personMethod();
return result + `, this.department = ${this.department}`;
}
managerMethod() {
// ...
}
}
const m = new Manager("Joe", "Bloggs", "Special Projects Manager", "Covert Ops");
console.log(m.personMethod());
vs.
// **ES5**
var Person = function(first, last) {
if (!(this instanceof Person)) {
throw new Error("Person is a constructor function, use new with it");
}
this.first = first;
this.last = last;
};
Person.prototype.personMethod = function() {
// ...
};
var Employee = function(first, last, position) {
if (!(this instanceof Employee)) {
throw new Error("Employee is a constructor function, use new with it");
}
Person.call(this, first, last);
this.position = position;
};
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.employeeMethod = function() {
// ...
};
var Manager = function(first, last, position, department) {
if (!(this instanceof Manager)) {
throw new Error("Manager is a constructor function, use new with it");
}
Employee.call(this, first, last, position);
this.department = department;
};
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
Manager.prototype.personMethod = function() {
var result = Employee.prototype.personMethod.call(this);
// ...use `result` for something...
return result;
};
Manager.prototype.managerMethod = function() {
// ...
};
Live-Beispiel:
// **ES5**
var Person = function(first, last) {
if (!(this instanceof Person)) {
throw new Error("Person is a constructor function, use new with it");
}
this.first = first;
this.last = last;
};
Person.prototype.personMethod = function() {
return "Result from personMethod: this.first = " + this.first + ", this.last = " + this.last;
};
var Employee = function(first, last, position) {
if (!(this instanceof Employee)) {
throw new Error("Employee is a constructor function, use new with it");
}
Person.call(this, first, last);
this.position = position;
};
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.personMethod = function() {
var result = Person.prototype.personMethod.call(this);
return result + ", this.position = " + this.position;
};
Employee.prototype.employeeMethod = function() {
// ...
};
var Manager = function(first, last, position, department) {
if (!(this instanceof Manager)) {
throw new Error("Manager is a constructor function, use new with it");
}
Employee.call(this, first, last, position);
this.department = department;
};
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
Manager.prototype.personMethod = function() {
var result = Employee.prototype.personMethod.call(this);
return result + ", this.department = " + this.department;
};
Manager.prototype.managerMethod = function() {
// ...
};
var m = new Manager("Joe", "Bloggs", "Special Projects Manager", "Covert Ops");
console.log(m.personMethod());
Wie Sie sehen können, gibt es dort viele wiederholte und ausführliche Dinge, die leicht falsch und langweilig sind, um sie erneut einzugeben (weshalb ich damals ein Skript dafür geschrieben habe ).
¹ "In ES2015-ES2018 class
gibt es nichts, was Sie mit Konstruktorfunktionen und Reflect.construct
(einschließlich Unterklassen Error
und Array
) nicht tun können. "
Beispiel:
// Creating an Error subclass:
function MyError(...args) {
return Reflect.construct(Error, args, this.constructor);
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;
MyError.prototype.myMethod = function() {
console.log(this.message);
};
// Example use:
function outer() {
function inner() {
const e = new MyError("foo");
console.log("Callng e.myMethod():");
e.myMethod();
console.log(`e instanceof MyError? ${e instanceof MyError}`);
console.log(`e instanceof Error? ${e instanceof Error}`);
throw e;
}
inner();
}
outer();
.as-console-wrapper {
max-height: 100% !important;
}