La nuova classsintassi è, per ora , principalmente zucchero sintattico. (Ma, sai, il buon tipo di zucchero.) Non c'è niente in ES2015-ES2020 che classpuò farlo che tu non possa fare con le funzioni del costruttore e Reflect.construct(incluse le sottoclassi Errore Array¹). (Si è probabile che ci saranno alcune cose in ES2021 che si possono fare con classche non si può fare altrimenti: campi privati , i metodi privati , e campi statici / metodi statici privati .)
Inoltre, è classun diverso tipo di OOP o è ancora l'eredità prototipica di JavaScript?
È la stessa eredità prototipica che abbiamo sempre avuto, solo con una sintassi più pulita e più conveniente se ti piace usare le funzioni di costruzione ( new Foo, ecc.). (In particolare nel caso di derivazione da Arrayo Error, cosa che non si poteva fare in ES5 e versioni precedenti. Ora è possibile con Reflect.construct[ spec , MDN ], ma non con il vecchio stile ES5.)
Posso modificarlo usando .prototype?
Sì, puoi ancora modificare l' prototypeoggetto nel costruttore della classe dopo aver creato la classe. Ad esempio, questo è perfettamente legale:
class Foo {
constructor(name) {
this.name = name;
}
test1() {
console.log("test1: name = " + this.name);
}
}
Foo.prototype.test2 = function() {
console.log("test2: name = " + this.name);
};
Ci sono vantaggi in termini di velocità?
Fornendo un idioma specifico per questo, suppongo sia possibile che il motore possa essere in grado di eseguire un lavoro migliore di ottimizzazione. Ma sono già terribilmente bravi a ottimizzare, non mi aspetterei una differenza significativa.
Quali vantaggi offre la classsintassi di ES2015 (ES6) ?
In breve: se non usi le funzioni di costruzione in primo luogo, preferendo Object.createo simili, classnon ti è utile.
Se usi le funzioni di costruzione, ci sono alcuni vantaggi a class:
La sintassi è più semplice e meno soggetta a errori.
È molto più facile (e di nuovo, meno soggetto a errori) impostare gerarchie di ereditarietà utilizzando la nuova sintassi rispetto alla vecchia.
classti difende dall'errore comune di non riuscire a usarlo newcon la funzione di costruzione (facendo in modo che il costruttore generi un'eccezione se thisnon è un oggetto valido per il costruttore).
Chiamare la versione del prototipo genitore di un metodo è molto più semplice con la nuova sintassi rispetto alla vecchia ( super.method()invece di ParentConstructor.prototype.method.call(this)o Object.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)).
Ecco un confronto della sintassi per una gerarchia:
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();
return result;
}
managerMethod() {
}
}
Esempio:
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.
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);
return result;
};
Manager.prototype.managerMethod = function() {
};
Esempio dal vivo:
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());
Come puoi vedere, ci sono molte cose ripetute e prolisse che è facile sbagliare e noioso da ridigitare (motivo per cui ho scritto uno script per farlo , nel corso della giornata).
¹ "Non c'è niente in ES2015-ES2018 che classpossa fare ciò che non puoi fare con le funzioni di costruzione e Reflect.construct(incluse le sottoclassi ErroreArray )"
Esempio:
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);
};
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;
}