La nueva class
sintaxis es, por ahora , principalmente azúcar sintáctica. (Pero, ya sabes, el buen tipo de azúcar). No hay nada en ES2015-ES2020 que class
pueda hacer que no puedas hacer con las funciones de constructor y Reflect.construct
(incluidas las subclases Error
y Array
¹). (Se es probable que haya algunas cosas en ES2021 que se puede hacer con class
que no se puede hacer de otra manera: los campos privados , los métodos privados , y los campos estáticos / métodos estáticos privados .)
Además, ¿es class
un tipo diferente de POO o sigue siendo la herencia prototípica de JavaScript?
Es la misma herencia prototípica que siempre hemos tenido, solo que con una sintaxis más limpia y conveniente si te gusta usar funciones constructoras ( new Foo
, etc.). (Particularmente en el caso de derivar de Array
o Error
, lo que no podía hacer en ES5 y versiones anteriores. Ahora puede hacerlo con Reflect.construct
[ spec , MDN ], pero no con el antiguo estilo ES5).
¿Puedo modificarlo usando .prototype
?
Sí, aún puede modificar el prototype
objeto en el constructor de la clase una vez que haya creado la clase. Por ejemplo, esto es perfectamente 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);
};
¿Hay beneficios de velocidad?
Al proporcionar un idioma específico para esto, supongo que es posible que el motor pueda hacer un mejor trabajo optimizando. Pero ya son muy buenos optimizando, no esperaría una diferencia significativa.
¿Qué beneficios ofrece la sintaxis de ES2015 (ES6) class
?
Brevemente: si no usa funciones de constructor en primer lugar, preferir Object.create
o similar, class
no es útil para usted.
Si usa funciones de constructor, existen algunos beneficios para class
:
La sintaxis es más simple y menos propensa a errores.
Es mucho más fácil (y de nuevo, menos propenso a errores) configurar jerarquías de herencia usando la nueva sintaxis que con la anterior.
class
lo defiende del error común de no usar new
con la función del constructor (al hacer que el constructor arroje una excepción si this
no es un objeto válido para el constructor).
Llamar a la versión del prototipo principal de un método es mucho más simple con la nueva sintaxis que con la anterior (en super.method()
lugar de ParentConstructor.prototype.method.call(this)
o Object.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)
).
Aquí hay una comparación de sintaxis para una jerarquía:
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() {
}
}
Ejemplo:
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() {
};
Ejemplo en 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 puede ver, hay muchas cosas repetidas y detalladas que es fácil equivocarse y aburrirse de volver a escribir (por eso escribí un guión para hacerlo , en el pasado).
¹ "No hay nada en ES2015-ES2018 que class
pueda hacer que usted no pueda hacer con las funciones del constructor y Reflect.construct
(incluidas las subclases Error
y Array
)"
Ejemplo:
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;
}