2012-08-07 18 views
80

He pasado las últimas horas tratando de encontrar una solución a mi problema, pero parece ser inútil.Cómo llamar a un método principal desde la clase secundaria en javascript?

Básicamente, necesito saber cómo llamar a un método principal de una clase secundaria. Todas las cosas que he intentado hasta ahora terminan o no funcionan o sobreescribo el método principal.

Estoy utilizando el código siguiente para configurar programación orientada a objetos en javascript:

// SET UP OOP 
// surrogate constructor (empty function) 
function surrogateCtor() {} 

function extend(base, sub) { 
    // copy the prototype from the base to setup inheritance 
    surrogateCtor.prototype = base.prototype; 
    sub.prototype = new surrogateCtor(); 
    sub.prototype.constructor = sub; 
} 

// parent class 
function ParentObject(name) { 
    this.name = name; 
} 
// parent's methods 
ParentObject.prototype = { 
    myMethod: function(arg) { 
     this.name = arg; 
    } 
} 

// child 
function ChildObject(name) { 
    // call the parent's constructor 
    ParentObject.call(this, name); 
    this.myMethod = function(arg) { 
     // HOW DO I CALL THE PARENT METHOD HERE? 
     // do stuff 
    } 
} 

// setup the prototype chain 
extend(ParentObject, ChildObject); 

tengo que llamar al método de los padres primero y luego añadir más cosas a ella en la clase hija.

En la mayoría de los lenguajes OOP sería tan simple como llamar al parent.myMethod() Pero realmente no puedo comprender cómo se hace en JavaScript.

¡Cualquier ayuda es muy apreciada, gracias!

Respuesta

123

Así es como se hace: ParentClass.prototype.myMethod();

O si lo desea llamar en el contexto de la instancia actual, que puede hacer: ParentClass.prototype.myMethod.call(this)

Lo mismo va para llamar a un método padres de la clase niño con argumentos: ParentClass.prototype.myMethod.call(this, arg1, arg2, ..) * Sugerencia: utilice apply() en lugar de call() para pasar argumentos como una matriz.

+7

Si desea llamar en el contexto de la instancia actual, que tiene que hacer 'ParentClass.prototype.myMethod.apply() o' ParentClass.prototype.myMethod.call() ', como lo hace con tu constructor – JMM

+3

Simplemente agregue que si desea llamar con argumentos, van dentro de la función aplicar o llamar ('ParentClass.prototype.myMethod.call (this, arg1, arg2, arg3 ...);') –

+0

No lo hago entender. Si llamo ParentClass.prototype.myMethod.call (esto); de myMethod de ChildObject, tengo un error "TypeError no capturado: no se puede leer la propiedad 'call' de undefined". – zhekaus

2

En caso de nivel de herencia múltiple, esta función se puede utilizar como un método super() en otros idiomas. Here is a demo fiddle, con algunas pruebas, puede usarlo así, dentro del uso de su método: call_base(this, 'method_name', arguments);

Hace uso de funciones ES bastante recientes, una compatibilidad con navegadores más antiguos no es garantía. Probado en IE11, FF29, CH35.

/** 
* Call super method of the given object and method. 
* This function create a temporary variable called "_call_base_reference", 
* to inspect whole inheritance linage. It will be deleted at the end of inspection. 
* 
* Usage : Inside your method use call_base(this, 'method_name', arguments); 
* 
* @param {object} object The owner object of the method and inheritance linage 
* @param {string} method The name of the super method to find. 
* @param {array} args The calls arguments, basically use the "arguments" special variable. 
* @returns {*} The data returned from the super method. 
*/ 
function call_base(object, method, args) { 
    // We get base object, first time it will be passed object, 
    // but in case of multiple inheritance, it will be instance of parent objects. 
    var base = object.hasOwnProperty('_call_base_reference') ? object._call_base_reference : object, 
    // We get matching method, from current object, 
    // this is a reference to define super method. 
      object_current_method = base[method], 
    // Temp object wo receive method definition. 
      descriptor = null, 
    // We define super function after founding current position. 
      is_super = false, 
    // Contain output data. 
      output = null; 
    while (base !== undefined) { 
     // Get method info 
     descriptor = Object.getOwnPropertyDescriptor(base, method); 
     if (descriptor !== undefined) { 
      // We search for current object method to define inherited part of chain. 
      if (descriptor.value === object_current_method) { 
       // Further loops will be considered as inherited function. 
       is_super = true; 
      } 
      // We already have found current object method. 
      else if (is_super === true) { 
       // We need to pass original object to apply() as first argument, 
       // this allow to keep original instance definition along all method 
       // inheritance. But we also need to save reference to "base" who 
       // contain parent class, it will be used into this function startup 
       // to begin at the right chain position. 
       object._call_base_reference = base; 
       // Apply super method. 
       output = descriptor.value.apply(object, args); 
       // Property have been used into super function if another 
       // call_base() is launched. Reference is not useful anymore. 
       delete object._call_base_reference; 
       // Job is done. 
       return output; 
      } 
     } 
     // Iterate to the next parent inherited. 
     base = Object.getPrototypeOf(base); 
    } 
} 
0

¿Qué tal algo basado en la idea de Douglas Crockford:

function Shape(){} 

    Shape.prototype.name = 'Shape'; 

    Shape.prototype.toString = function(){ 
     return this.constructor.parent 
      ? this.constructor.parent.toString() + ',' + this.name 
      : this.name; 
    }; 


    function TwoDShape(){} 

    var F = function(){}; 

    F.prototype = Shape.prototype; 

    TwoDShape.prototype = new F(); 

    TwoDShape.prototype.constructor = TwoDShape; 

    TwoDShape.parent = Shape.prototype; 

    TwoDShape.prototype.name = '2D Shape'; 


    var my = new TwoDShape(); 

    console.log(my.toString()); ===> Shape,2D Shape 
36

ES6 estilo permite el uso de nuevas características, tales como super palabra clave. super palabra clave, todo se trata del contexto de la clase padre, cuando usa la sintaxis de las clases ES6. Como un ejemplo muy sencillo, Salida:

class Foo { 
    static classMethod() { 
     return 'hello'; 
    } 
} 

class Bar extends Foo { 
    static classMethod() { 
     return super.classMethod() + ', too'; 
    } 
} 
Bar.classMethod(); // 'hello, too' 

Además, se puede utilizar para llamar super constructor de los padres:

class Foo {} 

class Bar extends Foo { 
    constructor(num) { 
     let tmp = num * 2; // OK 
     this.num = num; // ReferenceError 
     super(); 
     this.num = num; // OK 
    } 
} 

Y por supuesto que se puede utilizar para acceder a las propiedades de la clase padre super.prop. Entonces, use ES6 y sea feliz.

+1

¿Por qué esta respuesta no tiene más votos ascendentes? :) – fsinisi90

+2

@ fsinisi90 Creo que la pregunta no es sobre los métodos de clase de los padres, sino más bien sobre los métodos de instancia de los padres que simplemente no se pueden llamar con la palabra clave super a partir de ES6. – mcmlxxxiii

+0

funciona también para métodos que no son estáticos (probados con Chrome, sin transpiliing, sin probar la palabra clave estática) –

0

Bueno, para hacer esto, no está limitado con la abstracción de ES6 de Class. Acceder a los métodos prototipo del constructor padre es posible a través de la propiedad __proto__ (estoy bastante seguro de que habrá otros programadores JS para quejarse de que está depreciado) que se depreció pero al mismo tiempo descubrió que en realidad es una herramienta esencial para las necesidades de subclasificación (especialmente para las necesidades de subclases de Array, sin embargo).Entonces, mientras la propiedad __proto__ aún está disponible en todos los principales motores JS que conozco, ES6 introdujo la funcionalidad Object.getPrototypeOf() en la parte superior. La herramienta super() en la abstracción Class es un azúcar sintáctico de esto.

Por lo tanto, en caso de que no tenga acceso al nombre del constructor principal y no desee utilizar la abstracción Class, puede hacer lo siguiente;

function ChildObject(name) { 
    // call the parent's constructor 
    ParentObject.call(this, name); 
    this.myMethod = function(arg) { 
    //this.__proto__.__proto__.myMethod.call(this,arg); 
    Object.getPrototypeOf(Object.getPrototypeOf(this)).myMethod.call(this,arg); 
    } 
} 
Cuestiones relacionadas