Por ... en no ceder métodos

Nov 23 2020

Dado lo siguiente:

export class MyClass {
    public dataA = 0
    private dataB = 123
    public myMethod(): any {
        return {
            test: 'true'
        }
    }

    constructor() {
        for (const propOrMethod in this) {
            console.log({propOrMethod})
        }
    }
}

const myInst = new MyClass()

Ejecuto esto con ts-node index.tsy todo lo que obtengo es:

{ propOrMethod: 'dataA' }
{ propOrMethod: 'dataB' }

Sin referencia a myMethod. Me gustaría iterar sobre todos los métodos de mi clase, pero no parecen existir.

Respuestas

2 CertainPerformance Nov 24 2020 at 04:37

for..initera sobre todas las propiedades enumerables de la instancia y asciende por la cadena del prototipo. Pero los métodos normales en una clase no son enumerables:

class MyClass {
    myMethod() {
        return {
            test: 'true'
        };
    }
}
console.log(Object.getOwnPropertyDescriptor(MyClass.prototype, 'myMethod').enumerable);

Por lo que no se repite.

Si también desea iterar sobre propiedades no enumerables, use Object.getOwnPropertyNames(que itera sobre los propios nombres de propiedad del objeto , por lo que deberá hacerlo de forma recursiva si desea que todos los nombres de propiedad en cualquier lugar de la cadena del prototipo):

const recurseLog = obj => {
  for (const name of Object.getOwnPropertyNames(obj)) {
    console.log(name);
  }
  const proto = Object.getPrototypeOf(obj);
  if (proto !== Object.prototype) recurseLog(proto);
};
class MyClass {
    dataA = 0;
    dataB = 123;
    constructor() {
        recurseLog(this);
    }
    myMethod() {
        return {
            test: 'true'
        };
    }
}
const myInst = new MyClass();

También puede hacer que el método sea enumerable:

class MyClass {
    dataA = 0;
    dataB = 123;
    constructor() {
         for (const propOrMethod in this) {
            console.log({propOrMethod})
        }
    }
    myMethod() {
        return {
            test: 'true'
        };
    }
}
Object.defineProperty(MyClass.prototype, 'myMethod', { enumerable: true, value: MyClass.prototype.myMethod });
const myInst = new MyClass();

O asigne el método después de la definición de clase:

class MyClass {
    dataA = 0;
    dataB = 123;
    constructor() {
         for (const propOrMethod in this) {
            console.log({propOrMethod})
        }
    }
}
MyClass.prototype.myMethod = () => ({ test: 'true' });
const myInst = new MyClass();

O asígnelo a la instancia en el constructor:

class MyClass {
    dataA = 0;
    dataB = 123;
    constructor() {
        this.myMethod = this.myMethod;
         for (const propOrMethod in this) {
            console.log({propOrMethod})
        }
    }
     myMethod() {
        return {
            test: 'true'
        };
    }
}
const myInst = new MyClass();