Instancier les fonctions JavaScript avec des prototypes personnalisés

J'utilise la fonction suivante pour créer des instances de fonctions en JavaScript à partir d'un tableau d'arguments:

var instantiate = function (instantiate) { return function (constructor, args, prototype) { "use strict"; if (prototype) { var proto = constructor.prototype; constructor.prototype = prototype; } var instance = instantiate(constructor, args); if (proto) constructor.prototype = proto; return instance; }; }(Function.prototype.apply.bind(function () { var args = Array.prototype.slice.call(arguments); var constructor = Function.prototype.bind.apply(this, [null].concat(args)); return new constructor; })); 

En utilisant la fonction ci-dessus, vous pouvez créer des instances comme suit (voir le violon ):

 var f = instantiate(F, [], G.prototype); alert(f instanceof F); // false alert(f instanceof G); // true f.alert(); // F function F() { this.alert = function () { alert("F"); }; } function G() { this.alert = function () { alert("G"); }; } 

Le code ci-dessus fonctionne pour les constructeurs construits par l'utilisateur comme F Cependant, cela ne fonctionne pas pour les constructeurs indigènes comme Array pour des raisons de sécurité évidentes. Vous pouvez toujours créer un tableau, puis modifier sa propriété __proto__ mais j'utilise ce code dans Rhino, donc ça ne fonctionnera pas là-bas. Existe-t-il une autre façon d'obtenir le même résultat en JavaScript?

Vous ne pouvez pas sous-classer complètement un tableau .

Cependant, vous pouvez utiliser Object.create pour supprimer beaucoup de complexité de votre code actuel ( ex ).

Je ne pense pas que vous réalisez ce que vous souhaitez ici. Tout d'abord dans vos fonctions F et G, vous définissez une fonction d'alerte sur cet objet. Cela signifie que chaque fois que vous instanciez un objet, un nouvel objet de fonction sera créé et assigné à l'alerte. Ce n'est pas ce que vous voulez, vous devez définir l'alerte sur le prototype de F et G.

 function F() { } F.prototype.alert = function() { alert("F"); }; function G() { } G.prototype.alert = function() { alert("G"); }; 

Cependant, vous avez toujours un problème dans votre fonction instantable. Si vous l'appelez comme vous l'avez fait

 var f = instantiate(F, [], G.prototype); 

Tout ce que vous faites est de définir le prototype de f sur G.prototype, ce qui n'est pas ce que je pense que vous voulez. Je supposerais que si vous instanciez un objet F, vous voudriez pouvoir appeler toutes les fonctions définies sur F.prototype, mais la façon dont cela résiste, ce n'est pas le cas.

 function F() { } F.prototype.alert = function() { alert("F"); }; F.prototype.foo = function() { alert("F foo"); }; function G() { } G.prototype.alert = function() { alert("G"); }; var f = instantiate(F, [], G.prototype); f.foo(); // error! 

La raison de l'erreur ici est que j'ai dit que vous avez simplement attribué le prototype de f à G.prototype et que G.prototype n'a pas de définition de la fonction foo.

Si vous cherchez à faire des héritages de cette façon, regardez le blog de John Resig, il a une belle implémentation: http://ejohn.org/blog/simple-javascript-inheritance/

De plus, Douglas Crockford a préparé de bons exemples: http://www.crockford.com/javascript/inheritance.html