web-dev-qa-db-fra.com

Méthode d'appel utilisant un prototype JavaScript

Est-il possible d'appeler la méthode de base à partir d'une méthode prototype en JavaScript si elle a été remplacée?

MyClass = function(name){
    this.name = name;
    this.do = function() {
        //do somthing 
    }
};

MyClass.prototype.do = function() {  
    if (this.name === 'something') {
        //do something new
    } else {
        //CALL BASE METHOD
    }
};
127
markvpc

Je ne comprenais pas exactement ce que vous tentiez de faire, mais normalement, le comportement spécifique à un objet est appliqué comme suit:

function MyClass(name) {
    this.name = name;
}

MyClass.prototype.doStuff = function() {
    // generic behaviour
}

var myObj = new MyClass('foo');

var myObjSpecial = new MyClass('bar');
myObjSpecial.doStuff = function() {
    // do specialised stuff
    // how to call the generic implementation:
    MyClass.prototype.doStuff.call(this /*, args...*/);
}
198
Christoph

Une façon de le faire serait de sauvegarder la méthode de base, puis de l'appeler à partir de la méthode surchargée, comme

MyClass.prototype._do_base = MyClass.prototype.do;
MyClass.prototype.do = function(){  

    if (this.name === 'something'){

        //do something new

    }else{
        return this._do_base();
    }

};
24
Ramuns Usovs

Je crains que votre exemple ne fonctionne pas comme vous le pensez. Cette partie:

this.do = function(){ /*do something*/ };

écrase la définition de

MyClass.prototype.do = function(){ /*do something else*/ };

Puisque l'objet nouvellement créé a déjà une propriété "do", il ne recherche pas la chaîne de prototypes.

La forme classique de l'héritage en Javascript est difficile à comprendre. Je suggérerais d'utiliser plutôt le modèle de succession simple de Douglas Crockford. Comme ça:

function my_class(name) {
    return {
        name: name,
        do: function () { /* do something */ }
    };
}

function my_child(name) {
    var me = my_class(name);
    var base_do = me.do;
    me.do = function () {
        if (this.name === 'something'){
            //do something new
        } else {
            base_do.call(me);
        }
    }
    return me;
}

var o = my_child("something");
o.do(); // does something new

var u = my_child("something else");
u.do(); // uses base function

À mon avis, une méthode beaucoup plus claire de gestion des objets, des constructeurs et de l'héritage en javascript. Vous pouvez lire plus dans Crockfords Javascript: Les bonnes parties .

16
Magnar

Je sais que cet article date d'il y a 4 ans, mais à cause de mon arrière-plan C #, je cherchais un moyen d'appeler la classe de base sans avoir à spécifier le nom de la classe, mais plutôt à l'obtenir par une propriété de la sous-classe. Donc, mon seul changement à réponse de Christoph serait

À partir de ceci:

MyClass.prototype.doStuff.call(this /*, args...*/);

Pour ça:

this.constructor.prototype.doStuff.call(this /*, args...*/);
10
pholly

si vous définissez une fonction comme celle-ci (en utilisant la POO)

function Person(){};
Person.prototype.say = function(message){
   console.log(message);
}

il existe deux manières d'appeler une fonction prototype: 1) créer une instance et appeler la fonction objet:

var person = new Person();
person.say('hello!');

et l’autre voie est ... 2) appelle la fonction directement à partir du prototype:

Person.prototype.say('hello there!');
4
Alejandro Silva

Cette solution utilise Object.getPrototypeOf

TestA est super qui a getName

TestB est un enfant qui remplace getName mais a également getBothNames qui appelle la version super de getName ainsi que le child version

function TestA() {
  this.count = 1;
}
TestA.prototype.constructor = TestA;
TestA.prototype.getName = function ta_gn() {
  this.count = 2;
  return ' TestA.prototype.getName is called  **';
};

function TestB() {
  this.idx = 30;
  this.count = 10;
}
TestB.prototype = new TestA();
TestB.prototype.constructor = TestB;
TestB.prototype.getName = function tb_gn() {
  return ' TestB.prototype.getName is called ** ';
};

TestB.prototype.getBothNames = function tb_gbn() {
  return Object.getPrototypeOf(TestB.prototype).getName.call(this) + this.getName() + ' this object is : ' + JSON.stringify(this);
};

var tb = new TestB();
console.log(tb.getBothNames());
4
Manish Shrotriya

Une alternative :

// shape 
var shape = function(type){
    this.type = type;
}   
shape.prototype.display = function(){
    console.log(this.type);
}
// circle
var circle = new shape('circle');
// override
circle.display = function(a,b){ 
    // call implementation of the super class
    this.__proto__.display.apply(this,arguments);
}
4
Anum Malik
function NewClass() {
    var self = this;
    BaseClass.call(self);          // Set base class

    var baseModify = self.modify;  // Get base function
    self.modify = function () {
        // Override code here
        baseModify();
    };
}
4
Berezh

Si je comprends bien, vous voulez que la fonctionnalité de base soit toujours exécutée, tandis qu’une partie de celle-ci devrait être laissée aux implémentations.

Vous pourriez être aidé par le modèle de conception ' méthode du modèle '.

Base = function() {}
Base.prototype.do = function() { 
    // .. prologue code
    this.impldo(); 
    // epilogue code 
}
// note: no impldo implementation for Base!

derived = new Base();
derived.impldo = function() { /* do derived things here safely */ }
2
xtofl

Une autre méthode avec ES5 consiste à parcourir explicitement la chaîne de prototypes à l’aide de Object.getPrototypeOf(this)

const speaker = {
  speak: () => console.log('the speaker has spoken')
}

const announcingSpeaker = Object.create(speaker, {
  speak: {
    value: function() {
      console.log('Attention please!')
      Object.getPrototypeOf(this).speak()
    }
  }
})

announcingSpeaker.speak()
1
Max Fichtelmann

Si vous connaissez votre classe par son nom, vous pouvez faire quelque chose comme ceci:

function Base() {
}

Base.prototype.foo = function() {
  console.log('called foo in Base');
}

function Sub() {
}

Sub.prototype = new Base();

Sub.prototype.foo = function() {
  console.log('called foo in Sub');
  Base.prototype.foo.call(this);
}

var base = new Base();
base.foo();

var sub = new Sub();
sub.foo();

Cela va imprimer

called foo in Base
called foo in Sub
called foo in Base

comme prévu.

1
Michael

De plus, si vous voulez remplacer toutes les instances et pas seulement une instance spéciale, celle-ci pourrait vous aider.

function MyClass() {}

MyClass.prototype.myMethod = function() {
  alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
  MyClass.prototype.myMethod_original.call( this );
  alert( "doing override");
};

myObj = new MyClass();
myObj.myMethod();

résultat:

doing original
doing override
0
supertonsky

Non, vous devrez donner la fonction do dans le constructeur et la fonction do dans les noms différents du prototype.

0
ChrisInCambo