Souligner.js: comment enchainer les fonctions personnalisées

Utilisant Underscore.js , je peux écrire ce qui suit qui retourne 42 :

_([42, 43]).chain()
    .first()
    .value()

j'ai une fonction personnalisée, pas une partie de Underscore.js appelé double() :

function double(value) { return value * 2; };

je voudrais pouvoir appeler cette fonction dans une chaîne de soulignement, comme si elle faisait partie du soulignement. Je voudrais écrire ce qui suit, que je voudrais retourner 84 :

_([42, 43]).chain()
    .first()
    .double()
    .value()

cela ne peut pas fonctionner puisque Underscore ne définit pas double() . Je pourrais utiliser tap() comme dans:

_([42, 43]).chain()
    .first()
    .tap(double)
    .value()

ceci est valide, mais tap applique la fonction à son argument et renvoie l'argument, pas le résultat de la fonction. Il me semble donc que j'aurais besoin d'une sorte de tap qui renvoie le résultat de la fonction appliquée à son argument. Il y a quelque chose comme ça dans Underscore.js? Ai-je raté quelque chose de terriblement évident?

22
demandé sur Paul D. Waite 2010-10-15 23:59:44

7 réponses

ne pas trouver un tap qui retourne la valeur retourne par la fonction est exécute, Je définit un que je peux take et ajouter à _ :

_.mixin({take: function(obj, interceptor) {
    return interceptor(obj);
}});

en supposant que j'ai:

function double(value) { return value * 2; };

je peux écrire:

_([42, 43]).chain()
    .first()             // 42
    .take(double)        // Applies double to 42
    .value()             // 84

vous pouvez regarder take comme map sur des objets, au lieu de listes. Voulez expérimenter avec cela? Voir cet exemple sur jsFiddle .

23
répondu avernet 2010-10-20 23:15:45

vous avez donc une fonction personnalisée:

function double(value) { return value * 2; }

vous pouvez utiliser mixin pour étendre le soulignement avec elle:

_.mixin({ double:double });

Maintenant vous pouvez appeler votre fonction à partir de L'objet de soulignement _ :

_.double(42); // 84

et de l'objet enveloppé retourné de chain :

_([42, 43]).chain()
  .first()
  .double() // double made it onto the wrapped object too
  .value(); // 84
5
répondu Roatin Marth 2010-10-15 20:47:15

très bien, je suis en train de lire le code source annoté de underscore pour la première fois. Mais je pense que vous pouvez faire quelque chose comme ceci:

function double(value) { return value * 2; };

var obj = _([42, 43]).addToWrapper({double:double});

obj.chain()
  .first()
  .double()
  .value();

la syntaxe/les détails ne sont peut-être pas corrects, mais le point central est le suivant: lorsque vous appelez _([42,43]) , vous appelez le soulignement comme une fonction. Quand vous le faites, il instancie un nouvel objet et puis se mélange dans cet objet la plupart des fonctions de underscore. Puis, il retourne l'objet pour vous. Vous pouvez alors ajouter votre fonctions propres à cet objet, et rien de tout cela pollue le "_" espace de noms.

C'est ce que souligne.js code ressemblait à ça. Si je me trompe, j'aimerais savoir et j'espère que quelqu'un pourra expliquer pourquoi.

EDIT: j'ai en fait utilisé le underscore.js fortement pendant environ un mois maintenant, et je suis assez familier avec elle. J'ai maintenant savoir il se comporte comme je l'ai dit ici. Lorsque vous appelez _ en tant que fonction de constructeur, vous récupérez votre propre " namespace "(juste un objet), et vous pouvez y ajouter des choses avec addToWrapper () qui apparaissent dans votre namespace mais pas dans l'espace de noms" global""_". Donc la fonctionnalité que L'OP voulait est déjà intégrée. (Et j'ai été vraiment impressionné avec un trait de soulignement, btw, il est très très bien fait).

5
répondu Charlie Flowers 2010-12-22 09:19:56

plusieurs façons d'atteindre facilement ceci, voici une telle solution:

  _.chain([42,43])
    .first(1)
    .map(double)
    .first()
    .value();
    // 84

cependant, je recommande d'utiliser Ramda alors avec auto-curry et pipe / composer ces types de tâches sont triviales:

R.pipe(R.head, R.multiply(2))([42, 43]);  // 84

equivalent to:

R.compose(R.multiply(2), R.head)([42, 43]);  // 84

si vous souhaitez étendre la solution pour prendre dire les 2 premiers éléments, au lieu d'une seule valeur, comme demandé par L'OP, puis:

R.pipe(R.take(2), R.map(R.multiply(2)))([42, 43])  // [84, 86]

However, in Ramda R. composer is préféré. De toute façon, pour les tâches insignifiantes comme cela, il a tendance à être plus pratique et facile à utiliser.

0
répondu arcseldon 2014-11-23 15:28:30

ressemble à lodash a mis en œuvre exactement ce que vous recherchez:

_.thru(value, interceptor)

à partir de la documentation:

Cette méthode est comme _.appuyez sur, sauf qu'il retourne le résultat de interceptor

https://lodash.com/docs#thru

0
répondu Zaptree 2016-03-15 15:15:42

est-ce que map fonctionne pour ça?

_([42, 43]).chain()
    .first()
    .map(double)
    .value()

modifier

d'après la documentation, il semble que map ne fonctionne que si vous le placez avant l'appel à first :

_([42, 43]).chain()
    .map(double)
    .first()
    .value()
-1
répondu Gabe Moothart 2010-10-15 21:52:24

utiliser compose est une autre façon de gérer la situation, mais je pense que l'ajout d'une fonction telle que take comme je l'ai suggéré plus tôt est une meilleure solution. Pourtant, voici à quoi ressemblerait le code avec compose :

function double(value) { return value * 2; };

_.compose(
    double,
    _.first,
    _.bind(_.identity, _, [42, 43])
)();

La valeur initiale doit être fournie par une fonction qui retourne la valeur (ici fait par nourrissage identity ), et les fonctions doivent être répertoriés dans un autre qui est l'inverse de ce que vous avez avec une chaîne, ce qui me semble assez anormal.

-1
répondu avernet 2017-05-23 11:53:22