¿Puedo "extender" una "clase" definida por cierre en Javascript?

Resuelto James A. Rosen asked hace 14 años • 3 respuestas

Tengo una "clase" de Javascript definida así:

var Welcomer = function(name) {
  var pName = name;
  var pMessage = function() {
    return "Hi, " + pName + "!";
  };

  return {
    sayHi: function() {
      alert(pMessage());
    }
  };
};

new Welcomer('Sue').sayHi();

¿Hay alguna forma de "subclasificar" Welcomerde tal manera que pueda redefinir los métodos públicos y tener acceso a los métodos y variables privados? Lo siguiente me dará acceso a los métodos públicos, pero no a los privados:

var UnhappyWelcomer = function(name) {
  var pSadMessage = function() {
    // won't work, b/c I don't have access to pMessage
    return pMessage() + " Miserable day, innit?";
  };

  return {
    sayHi: function() {
      alert(pSadMessage());
    }
  };
};
UnhappyWelcomer.prototype = Welcomer(); // failed attempt at inheritance

new UnhappyWelcomer().sayHi();
James A. Rosen avatar Aug 25 '10 04:08 James A. Rosen
Aceptado

La respuesta simple a tu pregunta es No.

No puede hacer nada para obtener acceso a esas varcosas definidas, a menos que su función esté en el mismo alcance, o de alguna manera "haga pública" la información (devolviéndola o configurándola en this).

Sin embargo, si tiene acceso para editar la función original, puede reescribir las cosas de tal manera que esas funciones puedan "pasarse" a una función extendida, que puede alterar el alcance "protegido" del objeto. El siguiente código debería dar una buena idea de lo que estoy proponiendo.

var Welcomer = function(name) {
  var _protected = {
    name: name,
    message: function() {
      return "Hi, " + _protected.name + "!";
    }
  };

  return {
    extendWith: function(extender) {
      extender.call(this, _protected);
      return this;
    },
    sayHi: function() {
      alert(_protected.message());
    }
  };
};

var UnhappyWelcomer = function(name) {
  var self = Welcomer(name).extendWith(function(_protected) {
    _protected.sadMessage = function() {
       return _protected.message() + " Miserable day, innit?";
    };
    // extending the public while still having scope to _protected...
    this.sayHi = function() {
      alert(_protected.sadMessage());
    };
  });
  return self;
};

UnhappyWelcomer('bob').sayHi();
gnarf avatar Aug 24 '2010 21:08 gnarf

Ese patrón de "clase" no es un patrón de "clase", se conoce como patrón de módulo . Devuelve un objeto que no tiene vínculos con la función que lo creó aparte de la disponibilidad de sus variables privadas. El objeto devuelto NO es una instancia de la función que lo creó.

Cuando llamas a 'nueva Clase()', crea una instancia de esa función, pero también devuelve otro objeto. Cualquier operación adicional se realiza en realidad en el objeto devuelto y no en la instancia.

Para utilizar la herencia, realmente necesitas utilizar la herencia prototípica correctamente. Te sugiero que leas:

  • Herencia prototípica de Douglas Crockford
  • Miembros privados en JavaScript por Douglas Crockford
  • Prototipos y herencia en JavaScript por Scott Allen (nota: proto no es estándar)

Otras lecturas:

  • Herencia clásica en JavaScript http://javascript.crockford.com/inheritance.html

Lamento dejarte con material de lectura, pero me parece que estás explorando posibilidades. Estos artículos le darán una visión más profunda sobre el tema.

Una vez que sepas más sobre el asunto, lo más probable es que ignores a los miembros privados por completo y uses el prefijo _ y simplemente lo conviertas en un miembro público como todos los demás;) Es más fácil y los miembros privados no tienen sentido de todos modos.

BGerrissen avatar Aug 24 '2010 21:08 BGerrissen

Si realmente necesita herencia, existen algunas bibliotecas que le serán de gran ayuda. Una opción es trace.js , que de todos modos puede convertirse en una parte estándar de JavaScript en algún momento. Si eso no le convence, bibliotecas como jQuery y prototipo tienen ayudas para la herencia.

Si desea adoptar un enfoque mínimo/desde cero, le sugiero encarecidamente que utilice el modelo prototipo para todo. Verá un gran aumento en el rendimiento con respecto al patrón que tiene en sus ejemplos.

Para abordar más directamente su pregunta, no. Le resultará más fácil si diseña sus 'clases' de modo que no se dependa de funciones privadas.

jdc0589 avatar Aug 24 '2010 21:08 jdc0589