A nova class
sintaxe é, por enquanto , principalmente açúcar sintático. (Mas, você sabe, o bom tipo de açúcar.) Não há nada no ES2015-ES2020 que class
possa fazer que você não possa fazer com funções de construtor e Reflect.construct
(incluindo subclasses Error
e Array
¹). (Ela é provável que haverá algumas coisas em ES2021 que você pode fazer com class
que você não pode fazer o contrário: campos privados , métodos privados e campos estáticos / métodos estáticos privados .)
Além disso, é class
um tipo diferente de OOP ou ainda é a herança prototípica do JavaScript?
É a mesma herança prototípica que sempre tivemos, apenas com uma sintaxe mais limpa e conveniente se você gosta de usar funções construtoras ( new Foo
, etc.). (Particularmente no caso de derivar de Array
ou Error
, o que você não poderia fazer no ES5 e anteriores. Agora você pode com Reflect.construct
[ spec , MDN ], mas não com o antigo estilo ES5.)
Posso modificá-lo usando .prototype
?
Sim, você ainda pode modificar o prototype
objeto no construtor da classe depois de criar a classe. Por exemplo, isso é perfeitamente 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);
};
Existem benefícios de velocidade?
Ao fornecer um idioma específico para isso, suponho que seja possível que o motor seja capaz de fazer um trabalho melhor de otimização. Mas eles já são muito bons em otimizar, eu não esperaria uma diferença significativa.
Quais os benefícios que a class
sintaxe ES2015 (ES6) oferece?
Resumidamente: se você não usa funções construtoras em primeiro lugar, preferir Object.create
ou semelhante, class
não é útil para você.
Se você usar funções construtoras, existem alguns benefícios para class
:
A sintaxe é mais simples e menos sujeita a erros.
É muito mais fácil (e, novamente, menos sujeito a erros) configurar hierarquias de herança usando a nova sintaxe do que com a antiga.
class
o defende do erro comum de não usar new
a função do construtor (fazendo com que o construtor lance uma exceção se this
não for um objeto válido para o construtor).
Chamar a versão do protótipo pai de um método é muito mais simples com a nova sintaxe do que a antiga (em super.method()
vez de ParentConstructor.prototype.method.call(this)
ou Object.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)
).
Aqui está uma comparação de sintaxe para uma hierarquia:
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() {
}
}
Exemplo:
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() {
};
Exemplo ao 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());
Como você pode ver, há muitas coisas repetidas e prolixas que são fáceis de errar e chatas de redigitar (é por isso que escrevi um script para fazer isso , naquela época).
¹ "Não há nada no ES2015-ES2018 que class
possa fazer que você não possa fazer com funções de construtor e Reflect.construct
(incluindo subclasses Error
e Array
)"
Exemplo:
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;
}