2012-08-07 20 views
80

Spędziłem ostatnie kilka godzin próbując znaleźć rozwiązanie mojego problemu, ale wydaje się to beznadziejne.Jak wywołać metodę rodzica z klasy potomnej w javascript?

Zasadniczo muszę wiedzieć, jak wywołać metodę macierzystą z klasy dziecko. Wszystkie rzeczy, które próbowałem do tej pory, nie działają lub przepisują metodę nadrzędną.

Używam następujący kod do utworzenia OOP 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); 

muszę wywołać metodę rodzica, a następnie dodać trochę więcej rzeczy do niego w klasie podrzędnej.

W większości języków OOP, które byłyby tak proste, jak wywoływanie parent.myMethod() Ale naprawdę nie mogę zrozumieć, jak to się robi w javascript.

Każda pomoc jest doceniana, dziękuję!

Odpowiedz

123

Oto jak jej zrobić: ParentClass.prototype.myMethod();

Albo jeśli chcesz nazwać w kontekście bieżącej instancji, można zrobić: ParentClass.prototype.myMethod.call(this)

samo dotyczy wywołanie metody nadrzędnej z klasy dziecko z argumenty: ParentClass.prototype.myMethod.call(this, arg1, arg2, ..) * Wskazówka: użyj apply() zamiast call(), aby przekazać argumenty jako tablicę.

+7

Jeśli chcesz nazwać w kontekście bieżącej instancji, trzeba zrobić 'ParentClass.prototype.myMethod.apply() lub' ParentClass.prototype.myMethod.call() ', jak to zrobić z twoim konstruktorem. – JMM

+3

Wystarczy dodać, że jeśli chcesz wywoływać z argumentami, wchodzą one do funkcji apply lub call ('ParentClass.prototype.myMethod.call (this, arg1, arg2, arg3 ...);') –

+0

Nie mam Rozumiesz. Jeśli zadzwonię do ParentClass.prototype.myMethod.call (this); z myMethod ChildObject's, mam błąd "Uncaught TypeError: Can not read property 'call' of undefined". – zhekaus

2

W przypadku wielokrotnego dziedziczenia ta funkcja może być używana jako metoda super() w innych językach. Here is a demo fiddle, z kilkoma testami, możesz go używać w ten sposób, wewnątrz metody użycia: call_base(this, 'method_name', arguments);

Korzysta z zupełnie nowych funkcji ES, kompatybilność ze starszymi przeglądarkami nie jest gwarancją. Testowane w 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

Jak o czymś na bazie Douglas Crockforda pomysł:

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 styl pozwala na korzystanie z nowych funkcji, takich jak super hasła. super słowo kluczowe dotyczy kontekstu klasy nadrzędnej, gdy używana jest składnia klas ES6. W bardzo prosty przykład, kasie:

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

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

Ponadto, można użyć super wywołać konstruktora nadrzędny:

class Foo {} 

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

I oczywiście można go użyć, aby uzyskać dostęp właściwości klasy rodzic super.prop. Używaj ES6 i bądź szczęśliwy.

+1

Dlaczego ta odpowiedź nie ma więcej głosów w górze? :) – fsinisi90

+2

@ fsinisi90 Wydaje mi się, że pytanie nie dotyczy metod klasy rodzicielskiej, ale raczej metod instancji rodzica, które nie mogą być wywołane z super słowem kluczowym od wersji ES6. – mcmlxxxiii

+0

działa również dla metod, które nie są statyczne (testowane z Chrome, bez transpilingu, nie testowane słowo kluczowe static) –

0

Cóż, aby to zrobić, użytkownik nie jest ograniczony do abstrakcji ES6 w wersji Class. Uzyskanie dostępu do prototypowych metod macierzystego konstruktora jest możliwe za pośrednictwem właściwości __proto__ (jestem prawie pewien, że będą inni kodiści JS, którzy skarżą się, że jest ona amortyzowana), która jest amortyzowana, ale jednocześnie odkryła, że ​​jest to rzeczywiście niezbędne narzędzie do potrzeb podklasy (szczególnie dla potrzeb podklasy Array).Tak więc, chociaż właściwość __proto__ jest nadal dostępna we wszystkich głównych silnikach JS, które znam, ES6 wprowadziła na nim funkcję Object.getPrototypeOf(). Narzędzie super() w abstrakcji Class jest syntaktycznym cukrem tego.

Jeśli nie masz dostępu do nazwy konstruktora nadrzędnego i nie chcesz korzystać z abstrakcji Class, możesz nadal wykonywać następujące czynności;

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); 
    } 
} 
Powiązane problemy