50 votes

Comment hériter des fonctions javascript?

// Don't break the function prototype.
// pd - https://github.com/Raynos/pd
var proto = Object.create(Function.prototype, pd({
  "prop": 42
}));

var f = function() { return "is a function"; };
f.__proto__ = proto;

console.log(f.hasOwnProperty("prop")); // false
console.log(f.prop); // 42
console.log(f()); // "is a function"

.__proto__ est non-standard et obsolètes.

Comment suis-je censé hériter de fait la création d'un objet, mais ayant cet objet à une fonction.

Object.create renvoie un Objet n'est pas une Fonction.

new Constructor renvoie un Objet n'est pas une Fonction.

Motivation: - Une croix-navigateur finherit

var finherit = function (parent, child) {
    var f = function() { 
        parent.apply(this, arguments);
        child.apply(this, arguments);
    };
    f.__proto__ = parent;
    Object.keys(child).forEach(function _copy(key) {
        f[key] = child[key];
    });
    return f;
};

Je ne crois pas que cela soit possible, de sorte que nous devrions sans doute nous proposer un Function.create pour les es-discuter de la liste de diffusion

/*
  Creates a new function whose prototype is proto.
  The function body is the same as the function fbody.
  The hash of propertydescriptors props is passed to defineproperties just like
  Object.create does.
*/
Function.create = (function() {
  var functionBody = function _getFunctionBody(f) {
    return f.toString().replace(/.+\{/, "").replace(/\}$/, "");
  };
  var letters = "abcdefghijklmnopqrstuvwxyz".split("");

  return function _create(proto, fbody, props) {
    var parameters = letters.slice(0, fbody.length);
    parameters.push(functionBody(fbody));
    var f = Function.apply(this, parameters);
    f.__proto__ = proto;
    Object.defineProperties(f, props);
    return f;
  };
})();

Liées es-discuter mail

Comme mentionné dans l'es-discuter de fil, il existe un ES:strawman <| prototype de l'opérateur qui permettrait cela.

Nous allons voir à quoi cela ressemblerait à l'aide de <|

var f1 = function () {
  console.log("do things");
};

f1.method = function() { return 42; };

var f2 = f1 <| function () {
  super();
  console.log("do more things");
}
console.log(f1.isPrototypeOf(f2)); // true
console.log(f2()); // do things do more things
console.log(f2.hasOwnProperty("method")); // false
console.log(f2.method()); // 42

10voto

mr.stobbe Points 157

J'espère que je suis à la compréhension de ce droit.

Je crois que vous voulez un foncteur qui est à la fois une instance de l'avancement du prototype (oui, une classe, tout simplement pas un classique de la classe) ainsi que les appelle directement? Droit? Si oui, alors c'est parfaitement logique et est très flexible et puissant (surtout dans un très environnement asynchrone comme en JavaScript). Malheureusement, il n'y a aucun moyen de le faire avec élégance en JavaScript sans manipuler __proto__. Vous pouvez le faire en donnant une fonction anonyme et copie de toutes les références à toutes les méthodes (ce qui semble être la direction de la rubrique) pour agir comme un proxy de la classe. Les inconvénients de cette...

  1. C'est très coûteux en termes de temps d'exécution.
  2. (functorObj instanceof MyClass) ne sera jamais true.
  3. Les propriétés ne seront pas directement accessible (si ils ont été assignés par référence, ce serait une autre histoire, mais primitives qui sont affectés par valeur). Cela peut être résolu avec des accesseurs via defineProperty ou tout simplement nommé méthodes d'accès si nécessaire (il semble que c'est ce que vous cherchez, il suffit d'ajouter toutes les propriétés de l'foncteur avec defineProperty via des getters/setters au lieu de simplement les fonctions si vous n'avez pas besoin de la croix-support moteur/arrière de compatibilité).
  4. Vous êtes confronté à des cas limites où la finale prototypes natifs (comme Objet.prototype ou d'un Tableau.prototype [si vous êtes à hériter de ce]) peut ne pas fonctionner comme prévu.
  5. Appelant functorObj(someArg) sera toujours faire de l' this contexte, être l'objet, indépendamment de si elle est appelée functorObj.call(someOtherObj, someArg) (ce n'est pas le cas pour les appels de méthode)
  6. Parce que le foncteur objet est créé au moment de la demande, il sera verrouillé dans le temps et en manipulant le prototype initial ne sera pas affecter l'allocation d'un foncteur des objets comme un objet normal serait affecté (modification de Maclasse.prototype n'affectera pas le foncteur des objets, et l'inverse est vrai aussi).

Si vous l'utilisez, doucement mais, rien de tout cela devrait être une grosse affaire.

Dans votre prototype de votre classe à définir quelque chose comme...

// This is you're emulated "overloaded" call() operator.
MyClass.prototype.execute = function() {
   alert('I have been called like a function but have (semi-)proper access to this!');
};

MyClass.prototype.asFunctor = function(/* templateFunction */) {
   if ((typeof arguments[0] !== 'function') && (typeof this.execute !== 'function'))
      throw new TypeError('You really should define the calling operator for a functor shouldn\'t you?');
   // This is both the resulting functor proxy object as well as the proxy call function
   var res = function() {
      var ret;
      if (res.templateFunction !== null)
         // the this context here could be res.asObject, or res, or whatever your goal is here
         ret = res.templateFunction.call(this, arguments);
      if (typeof res.asObject.execute === 'function')
         ret = res.asObject.execute.apply(res.asObject, arguments);
      return ret;
   };
   res.asObject = this;
   res.templateFunction = (typeof arguments[0] === 'function') ? arguments[0] : null;
   for (var k in this) {
      if (typeof this[k] === 'function') {
         res[k] = (function(reference) {
            var m = function() {
               return m.proxyReference.apply((this === res) ? res.asObject : this, arguments);
            };
            m.proxyReference = reference;
            return m;
         })(this.asObject[k]);
      }
   }
   return res;
};

Résultant de l'utilisation ressemblerait à quelque chose comme...

var aobj = new MyClass();
var afunctor = aobj.asFunctor();
aobj.someMethodOfMine(); // << works
afunctor.someMethodOfMine(); // << works exactly like the previous call (including the this context).
afunctor('hello'); // << works by calling aobj.execute('hello');

(aobj instanceof MyClass) // << true
(afunctor instanceof MyClass) // << false
(afunctor.asObject === aobj) // << true

// to bind with a previous function...
var afunctor = (new MyClass()).asFunctor(function() { alert('I am the original call'); });
afunctor() // << first calls the original, then execute();
// To simply wrap a previous function, don't define execute() in the prototype.

Vous pourriez même chaîne se lier d'innombrables autres objets/fonctions/etc jusqu'à ce que les vaches sont venus à la maison. Juste refactoriser le proxy appeler un peu.

Espérons que cela aide. Oh, et bien sûr, vous pourriez changer l'usine de flux de sorte qu'un constructeur appelé sans le new opérateur instancie un nouvel objet et renvoie le foncteur de l'objet. Toutefois vous préférez (vous pouvez certainement le faire par d'autres moyens).

Enfin, pour toute fonction devenir l'exécution de l'opérateur pour un foncteur en un peu plus élégant d'une manière, il suffit de faire le proxy fonction d'une méthode de Function.prototype et passer à l'objet de retour si vous voulez faire quelque chose comme (vous pouvez swap templateFunction avec this et this avec l'argument de cours)...

var functor = (function() { /* something */ }).asFunctor(aobj);

-3voto

Don Rhummy Points 2517

Héritant des fonctions sur leur propre n'a pas de sens. L'héritage est destinée à permettre aux objets d'avoir la même interface et les fonctionnalités, mais avec quelques différences dans la façon dont cette fonctionnalité joue.

Par exemple, vous pourriez avoir une classe InputField qui permet aux utilisateurs de saisir du texte et de la lecture de texte (et l'affiche sur un écran). Quelque part le long de la ligne, vous pourriez découvrir que vous avez besoin d'un champ qui cache tout ce qui est tapé dans l'il, et vous appelez cela un PasswordField. Au lieu de réécrire tout le code qui est commune à InputField, vous héritez de. Il vous suffit de changer la façon dont il est affiché. Et cela s'ajoute un autre avantage: vous pouvez passer PasswordField à rien d'attendre une InputField et ils peuvent interagir parfaitement avec aucun besoin de modifier leur code. C'est parce que le "contrat" ou "interface" est le même.

Cependant, héritant d'une seule fonction n'a pas de sens tant que vous n'êtes pas garder toutes les fonctionnalités de base du même et de l'interface à changer (dans le cadre d'une interface est le NOM des fonctions, ce qui vous auriez à changer à leur différentes fonctions). Si vous avez conservé les noms de fonction de même, il n'y aurait aucun moyen pour l'exécution de la machine pour savoir qui appeler et il serait trompeur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X