Resumen
En ES6, class (clase) se introduce como plantilla para objetos; se puede definir una clase mediante la palabra clave class.
La esencia de class es function.
Se puede considerar como azúcar sintáctico, haciendo que la escritura del prototipo de objetos sea más clara y más parecida a la sintaxis de la programación orientada a objetos.
Uso básico
Definición de clase
Las expresiones de clase pueden ser anónimas o con nombre.
let Example = class {
constructor(a) {
this.a = a;
}
}
let Example = class Example {
constructor(a) {
this.a = a;
}
}
Declaración de clase
class Example {
constructor(a) {
this.a = a;
}
}
Punto importante: no se puede declarar repetidamente.
class Example{}
class Example{}
let Example1 = class{}
class Example{}
Puntos a tener en cuenta
Las definiciones de clase no se elevan (hoisting), lo que significa que la clase debe definirse antes de acceder a ella; de lo contrario, se producirá un error.
Los métodos de la clase no necesitan la palabra clave function.
No se pueden agregar punto y coma entre métodos.
new Example();
class Example {}
El cuerpo de la clase
Propiedades
prototype
En ES6, prototype todavía existe; aunque se pueden definir métodos directamente en la clase, en realidad los métodos se definen en prototype.
Sobrescribir métodos / Agregar métodos durante la inicialización
Agregar métodos
Object.assign(Example.prototype,{
})
Propiedades estáticas
Propiedades estáticas: son propiedades de la propia clase, es decir, propiedades definidas directamente dentro de la clase (Class.propname), que no requieren instanciación.
En ES6 se estipula que dentro de Class solo hay métodos estáticos, no propiedades estáticas.
class Example {
static a = 2;
}
Example.b = 2;
Propiedades públicas
class Example{}
Example.prototype.a = 2;
Propiedades de instancia
Propiedades de instancia: propiedades definidas en el objeto de instancia (this).
class Example {
a = 2;
constructor () {
console.log(this.a);
}
}
Propiedad name
Devuelve el nombre de la clase que sigue a class (si existe).
let Example=class Exam {
constructor(a) {
this.a = a;
}
}
console.log(Example.name);
let Example=class {
constructor(a) {
this.a = a;
}
}
console.log(Example.name);
Métodos
Método constructor
El método constructor es el método predeterminado de la clase y se llama al crear un objeto instanciado de la clase.
class Example{
constructor(){
console.log('Soy constructor');
}
}
new Example();
Devolver objeto
class Test {
constructor(){
}
}
console.log(new Test() instanceof Test);
class Example {
constructor(){
return new Test();
}
}
console.log(new Example() instanceof Example);
Métodos estáticos
class Example{
static sum(a, b) {
console.log(a+b);
}
}
Example.sum(1, 2);
Métodos de prototipo
class Example {
sum(a, b) {
console.log(a + b);
}
}
let exam = new Example();
exam.sum(1, 2);
Métodos de instancia
class Example {
constructor() {
this.sum = (a, b) => {
console.log(a + b);
}
}
}
Instanciación de la clase
new
La instanciación de class debe realizarse mediante la palabra clave new.
class Example {}
let exam1 = Example();
Objeto instanciado
Compartir objeto prototipo
class Example {
constructor(a, b) {
this.a = a;
this.b = b;
console.log('Example');
}
sum() {
return this.a + this.b;
}
}
let exam1 = new Example(2, 1);
let exam2 = new Example(3, 1);
console.log(Object.getPrototypeOf(exam1) === Object.getPrototypeOf(exam2));
Object.getPrototypeOf(exam1).sub = function() {
return this.a - this.b;
}
console.log(exam1.sub());
console.log(exam2.sub());
decorator
decorator es una función que se utiliza para modificar el comportamiento de la clase y tiene efecto en el momento de la compilación del código.
Decorador de clase
Un parámetro
El primer parámetro target, apunta a la clase en sí.
function testable(target) {
target.isTestable = true;
}
@testable
class Example {}
Example.isTestable;
Múltiples parámetros: implementación anidada
function testable(isTestable) {
return function(target) {
target.isTestable=isTestable;
}
}
@testable(true)
class Example {}
Example.isTestable;
Propiedades de instancia
Los dos ejemplos anteriores agregan propiedades estáticas; si se desea agregar propiedades de instancia, basta con operar sobre el prototype de la clase.
Decorador de método
3 parámetros: target (objeto prototipo de la clase), name (nombre de la propiedad decorada), descriptor (objeto descriptivo de la propiedad).
class Example {
@writable
sum(a, b) {
return a + b;
}
}
function writable(target, name, descriptor) {
descriptor.writable = false;
return descriptor;
}
Orden de ejecución de los decoradores
Entran de afuera hacia adentro, se ejecutan de adentro hacia afuera.
class Example {
@logMethod(1)
@logMethod(2)
sum(a, b){
return a + b;
}
}
function logMethod(id) {
console.log('evaluated logMethod'+id);
return (target, name, desctiptor) => console.log('excuted logMethod '+id);
}
Encapsulamiento y herencia
getter / setter
Definición
class Example{
constructor(a, b) {
this.a = a;
this.b = b;
}
get a(){
console.log('getter');
return this.a;
}
set a(a){
console.log('setter');
this.a = a;
}
}
let exam = new Example(1,2);
class Example1{
constructor(a, b) {
this.a = a;
this.b = b;
}
get a(){
console.log('getter');
return this._a;
}
set a(a){
console.log('setter');
this._a = a;
}
}
let exam1 = new Example1(1,2);
console.log(exam1._a);
getter no puede aparecer solo
class Example {
constructor(a) {
this.a = a;
}
get a() {
return this.a;
}
}
let exam = new Example(1);
getter y setter deben aparecer al mismo nivel
class Father {
constructor(){}
get a() {
return this._a;
}
}
class Child extends Father {
constructor(){
super();
}
set a(a) {
this._a = a;
}
}
let test = new Child();
test.a = 2;
console.log(test.a);
class Father1 {
constructor(){}
get a() {
return this._a;
}
set a(a) {
this._a = a;
}
}
class Child1 extends Father1 {
constructor(){
super();
}
}
let test1 = new Child1();
test1.a = 2;
console.log(test1.a);
extends
La herencia de clases se implementa mediante extends.
class Child extends Father { ... }
super
En el método constructor de la subclase debe haber super, y debe aparecer antes de this.
class Father {
constructor() {}
}
class Child extends Father {
constructor() {}
}
let test = new Child();
La llamada al constructor de la clase padre solo puede aparecer en el constructor de la subclase.
class Father {
test(){
return 0;
}
static test1(){
return 1;
}
}
class Child extends Father {
constructor(){
super();
}
}
class Child1 extends Father {
test2() {
super();
}
}
Al llamar métodos de la clase padre, super como objeto, en métodos normales apunta al objeto prototipo de la clase padre; en métodos estáticos, apunta a la clase padre.
class Child2 extends Father {
constructor(){
super();
console.log(super.test());
}
static test3(){
return super.test1+2;
}
}
Child2.test3();
Puntos a tener en cuenta
No se puede heredar de objetos normales.
var Father = {
}
class Child extends Father {
}
Object.setPrototypeOf(Child.prototype, Father);