Seleccionar página

Los métodos son una de las partes más importantes de las clases, ya que en ellos incluimos las funciones que queremos que trabajen sobre nuestro objeto. Los métodos tienen un modelo específico de definición y funcionamiento.

métodos en el prototipo

classfunction
class C {
  method () {
    return 2;
  }
}

const c = new C();
console.assert( c.method() === 2 );
function C () {
}
C.prototype.method = function () {
  return 2;
};

const c = new C();
console.assert( c.method() === 2 );

En class los métodos se escriben dentro del cuerpo de la clase, de forma similar a como hacemos con el constructor. Estas funciones se se incorporan automáticamente como miembros del prototipo de la clase.

Con function debemos añadir directamente los métodos como miembro del objeto prototype para que se comporten de igual forma que con class.

    métodos en el objeto

    classfunction
    class C {
      constructor () {
        this.method1 = function () {
          return 1;
        }
      }
      method2 () {
        return 2;
      }
    }
    
    const c = new C();
    console.assert( c.method1() === 1 );
    console.assert( !('method1' in C.prototype) );
    console.assert( c.method2() === 2 );
    console.assert( 'method2' in C.prototype );
    
    function C () {
      this.method1 = function () {
        return 1;
      }
    }
    C.prototype.method2 = function () {
      return 2;
    };
    
    const c = new C();
    console.assert( c.method1() === 1 );
    console.assert( !('method1' in C.prototype) );
    console.assert( c.method2() === 2 );
    console.assert( 'method2' in C.prototype );
    

    En general los métodos se definen a nivel de prototipo, ya que compartir las funciones entre todos los objetos de la misma clase no causa ningún conflicto. No obstante, nada nos impide crear métodos directamente sobre el objeto, por ejemplo, en el constructor. A partir de ese momento estos métodos son parte del objeto y no de su prototipo.

      métodos no enumerables

      classfunction
      class C {
        method () {
        }
      }
      
      console.assert(
        ! C.prototype.propertyIsEnumerable( 'method' )
      );
      
      const c = new C();
      console.assert(
        ! c.propertyIsEnumerable( 'method' )
      );
      
      function C () {
      }
      C.prototype.method = function () {
        return 1;
      };
      
      console.assert(
        C.prototype.propertyIsEnumerable( 'method' )
      );
      
      const c = new C();
      console.assert(
        ! c.propertyIsEnumerable( 'method' )
      );
      

      Los miembros creados sobre el prototipo no son enumerables en el objeto, es decir, no son significativos a la hora de recorrer las propiedades del objeto en un bucle for...in. En el caso de utilizar function, normalmente el método es enumerable en el prototipo, pero deja de ser enumerable en el objeto. Cualquier configuración que hagamos sobre enumeración en los miembros del prototipo no tendrá efecto sobre el objeto.

      Los métodos creados directamente sobre el objeto son enumerables, y eso no suele ser el comportamiento que deseamos, por lo que suele ser conveniente utilizar Object.defineProperty() o Object.defineProperties() para cambiar su condición a no enumerables.

      classfunction
      class C {
        constructor () {
          Object.defineProperty( this, 'method', {
            value      : function () {
              return 1;
            },
            enumerable : false
          } );
        }
      }
      
      const c = new C();
      console.assert(
        ! c.propertyIsEnumerable( 'method' )
      );
      
      function C () {
        Object.defineProperty( this, 'method', {
          value      : function () {
            return 1;
          },
          enumerable : false
        } );
      }
      
      const c = new C();
      console.assert(
        ! c.propertyIsEnumerable( 'method' )
      );
      

      Aunque lo habitual es dejar los métodos como no enumerables, en nuestra mano decidir como queremos que se comporten los métodos a este respecto.

      this

      Cuando se ejecutan los métodos tendrán this dirigido al objeto concreto en el que se está invocando el método y no a la función.

      classfunction
      class C {
        method () {
          console.assert( this instanceof C );
        }
      }
      
      const c = new C();
      c.method();
      
      function C () {
      }
      C.prototype.method = function () {
        console.assert( this instanceof C );
      };
      
      const c = new C();
      c.method();
      

      Tenemos que saber que cuando se invoca a un método es posible modificar su this por medio de los parámetros de los métodos .call() y .apply() que tiene todas las funciones.

      strict mode

      classfunction
      class C {
        constructor () {
          a = 10;  /* throw an error in strict mode */
        }
      }
      
      try {
        const c = new C();
        console.assert( false );
      } catch (err) {
        console.assert(
          err.message === 'a is not defined'
        );
      }
      
      function C () {
        'use strict';
        a = 10;  /* throw an error in strict mode */
      }
      
      try {
        const c = new C();
        console.assert( false );
      } catch (err) {
        console.assert(
          err.message === 'a is not defined'
        );
      }
      

      Los constructores y métodos definidos en una instrucción class son ejecutados implicitamente bajo la cláusula script mode. Esto suele ser bastante útil para asegurarnos que utilizamos un Javascript bien construido.

      Por el contrario, en el caso de function la cláusula script mode debe ser incluida de forma explícita para evitar los problemas de funcionamiento en sloppy mode o modo poco riguroso.

      propiedades Índicemétodos de acceso y datos privados