Quel est le moyen le plus rapide de cloner une fonction en JavaScript (avec ou sans ses propriétés)?
Deux options qui viennent à l'esprit sont eval(func.toString())
et function() { return func.apply(..) }
. Mais je suis préoccupé par les performances de l'évaluation et le wrapping aggravera la pile et dégradera probablement les performances s'il est appliqué beaucoup ou appliqué à déjà enveloppé.
new Function(args, body)
ça a l'air sympa, mais comment puis-je diviser de manière fiable une fonction existante en args et body sans analyseur JS dans JS?
Merci d'avance.
Mise à jour: ce que je veux dire, c'est être capable de faire
var funcB = funcA.clone(); // where clone() is my extension
funcB.newField = {...}; // without affecting funcA
javascript
function
Andrey Shchekin
la source
la source
Réponses:
essaye ça:
la source
Voici une réponse mise à jour
Cependant
.bind
est une fonctionnalité moderne (> = iE9) de JavaScript (avec une solution de contournement de compatibilité de MDN )Remarques
Il ne clone pas les propriétés attachées supplémentaires de l'objet fonction , y compris la propriété prototype . Crédit à @jchook
La nouvelle fonction de cette variable est bloquée avec l'argument donné sur bind (), même sur les nouveaux appels de fonction apply (). Crédit à @Kevin
la source
newFunc
n'aura PAS son propre prototype pour lesnew newFunc
instances, alors que leoldFunc
sera.var f = function() { console.log('hello ' + this.name) }
lorsqu'il est lié à{name: 'Bob'}
imprime «bonjour Bob».f.apply({name: 'Sam'})
affichera également «bonjour Bob», en ignorant l'objet «this».function () { [native code] }
au lieu du contenu complet de la fonction.Voici une version légèrement meilleure de la réponse de Jared. Celui-ci ne se retrouvera pas avec des fonctions profondément imbriquées plus vous clonerez. Il appelle toujours l'original.
De plus, en réponse à la réponse mise à jour donnée par pico.creator, il convient de noter que la
bind()
fonction ajoutée dans Javascript 1.8.5 a le même problème que la réponse de Jared - elle continuera à s'emboîter causant des fonctions de plus en plus lentes à chaque fois qu'elle est utilisée.la source
Étant curieux mais toujours incapable de trouver la réponse au sujet de performance de la question ci-dessus, j'ai écrit cet essentiel pour nodejs afin de tester à la fois les performances et la fiabilité de toutes les solutions présentées (et notées).
J'ai comparé les temps de mur de la création d'une fonction de clone et de l'exécution d'un clone. Les résultats ainsi que les erreurs d'assertion sont inclus dans le commentaire de l'essentiel.
Plus mes deux cents (basé sur la suggestion de l'auteur):
clone0 cent (plus rapide mais plus laid):
clone4 cent (plus lent mais pour ceux qui n'aiment pas eval () à des fins connues seulement d'eux et de leurs ancêtres):
En ce qui concerne les performances, si eval / new Function est plus lent que la solution wrapper (et cela dépend vraiment de la taille du corps de la fonction), cela vous donne un clone de fonction nue (et je veux dire le vrai clone superficiel avec des propriétés mais un état non partagé) sans fuzz inutile avec des propriétés cachées, des fonctions de wrapper et des problèmes avec la pile.
De plus, il y a toujours un facteur important à prendre en compte: moins il y a de code, moins il y a d'erreurs.
L'inconvénient de l'utilisation de la fonction eval / new est que le clone et la fonction d'origine fonctionneront dans des portées différentes. Cela ne fonctionnera pas bien avec les fonctions qui utilisent des variables de portée. Les solutions utilisant un wrapping de type bind sont indépendantes de la portée.
la source
Object.assign(newfun.prototype, this.prototype);
avant l'instruction return (version propre), votre méthode est la meilleure réponse.C'était assez excitant de faire fonctionner cette méthode, donc cela fait un clone d'une fonction en utilisant l'appel de fonction.
Certaines limitations concernant les fermetures décrites dans MDN Function Reference
Prendre plaisir.
la source
Bref et simple:
la source
la source
la source
originalFunction
, mais ne l'exécutera pas réellement lorsque vous exécuterezclonedFunction
, ce qui est inattendu.Cette réponse s'adresse aux personnes qui voient le clonage d'une fonction comme la réponse à leur utilisation souhaitée, mais qui n'ont pas vraiment besoin de cloner une fonction, car ce qu'elles veulent vraiment, c'est simplement pouvoir attacher différentes propriétés à la même fonction, mais seulement déclarer cette fonction une fois.
Pour ce faire, créez une fonction de création de fonction:
Ce n'est pas exactement la même chose que celle que vous avez décrite, cependant, cela dépend de la façon dont vous souhaitez utiliser la fonction que vous souhaitez cloner. Cela utilise également plus de mémoire car il crée en fait plusieurs copies de la fonction, une fois par appel. Cependant, cette technique peut résoudre le cas d'utilisation de certaines personnes sans avoir besoin d'une
clone
fonction compliquée .la source
Je me demande simplement - pourquoi voudriez-vous cloner une fonction alors que vous avez des prototypes ET pouvez définir la portée d'un appel de fonction à tout ce que vous souhaitez?
la source
Si vous souhaitez créer un clone à l'aide du constructeur Function, quelque chose comme ceci devrait fonctionner:
Un test simple:
Cependant, ces clones perdront leurs noms et la portée de toutes les variables fermées.
la source
J'ai modifié la réponse de Jared à ma manière:
1) maintenant, il prend en charge le clonage des constructeurs (peut appeler avec new); dans ce cas ne prend que 10 arguments (vous pouvez le faire varier) - en raison de l'impossibilité de passer tous les arguments dans le constructeur d'origine
2) tout est correctement fermé
la source
arguments[0], arguments[1] /*[...]*/
pourquoi n'utilisez-vous pas simplement...arguments
? 1) Il n'y a pas de dépendance concernant le nombre d'arguments (ici limité à 10) 2) plus courtBien que je ne recommanderais jamais d'utiliser cela, j'ai pensé que ce serait un petit défi intéressant de trouver un clone plus précis en prenant certaines des pratiques qui semblaient être les meilleures et en les corrigeant un peu. Voici le résultat des journaux:
la source
Cette fonction de clonage:
Notez que cette version n'effectue qu'une copie superficielle. Si votre fonction a des objets comme propriétés, la référence à l'objet d'origine est conservée (même comportement que Object spread ou Object.assign). Cela signifie que la modification des propriétés profondes dans la fonction clonée affectera l'objet référencé dans la fonction d'origine!
la source