tl; dr: Est-il possible de rendre un modèle réutilisable littéral?
J'ai essayé d'utiliser des modèles littéraux, mais je suppose que je ne comprends tout simplement pas et que maintenant je suis frustré. Je veux dire, je pense que je comprends, mais "ça" ne devrait pas être comment ça marche, ni comment ça devrait arriver. Cela devrait être différent.
Tous les exemples que je vois (même les modèles étiquetés) nécessitent que les "substitutions" soient effectuées au moment de la déclaration et non au moment de l'exécution, ce qui me semble totalement inutile pour un modèle. Peut-être que je suis fou, mais un "modèle" pour moi est un document qui contient des jetons qui sont substitués lorsque vous l'utilisez, pas lorsque vous le créez, sinon c'est juste un document (c'est-à-dire une chaîne). Un modèle est stocké avec les jetons sous forme de jetons et ces jetons sont évalués lorsque vous ... l'évaluez.
Tout le monde cite un exemple horrible semblable à:
var a = 'asd';
return `Worthless ${a}!`
C'est bien, mais si je sais déjà a
, je le ferais simplement return 'Worthless asd'
ou return 'Worthless '+a
. À quoi ça sert? Sérieusement. Ok, le point est la paresse; moins d'avantages, plus de lisibilité. Génial. Mais ce n'est pas un modèle! Pas à mon humble avis. Et MHO est tout ce qui compte! Le problème, à mon humble avis, est que le modèle est évalué lorsqu'il est déclaré, donc, si vous le faites, à mon humble avis:
var tpl = `My ${expletive} template`;
function go() { return tpl; }
go(); // SPACE-TIME ENDS!
Puisque expletive
n'est pas déclaré, il génère quelque chose comme My undefined template
. Super. En fait, dans Chrome au moins, je ne peux même pas déclarer le modèle; il jette une erreur car expletive
n'est pas défini. Ce dont j'ai besoin, c'est de pouvoir effectuer la substitution après avoir déclaré le modèle:
var tpl = `My ${expletive} template`;
function go() { return tpl; }
var expletive = 'great';
go(); // My great template
Cependant, je ne vois pas comment cela est possible, car ce ne sont pas vraiment des modèles. Même quand vous dites que je devrais utiliser des balises, non, elles ne fonctionnent pas:
> explete = function(a,b) { console.log(a); console.log(b); }
< function (a,b) { console.log(a); console.log(b); }
> var tpl = explete`My ${expletive} template`
< VM2323:2 Uncaught ReferenceError: expletive is not defined...
Tout cela m'a conduit à croire que les littéraux de modèle sont horriblement mal nommés et devraient être appelés ce qu'ils sont vraiment: heredocs . Je suppose que la partie "littérale" aurait dû me prévenir (comme dans, immuable)?
Est-ce que je manque quelque chose? Existe-t-il un (bon) moyen de rendre littéral un modèle réutilisable?
Je vous donne, des littéraux de modèle réutilisables :
> function out(t) { console.log(eval(t)); }
var template = `\`This is
my \${expletive} reusable
template!\``;
out(template);
var expletive = 'curious';
out(template);
var expletive = 'AMAZING';
out(template);
< This is
my undefined reusable
template!
This is
my curious reusable
template!
This is
my AMAZING reusable
template!
Et voici une fonction "helper" naïve ...
function t(t) { return '`'+t.replace('{','${')+'`'; }
var template = t(`This is
my {expletive} reusable
template!`);
...Pour le faire mieux".
J'ai tendance à les appeler des guterals modèles en raison de la zone à partir de laquelle ils produisent des sentiments sinueux.
<strike>
balise.Réponses:
Pour que ces littéraux fonctionnent comme les autres moteurs de modèles, il doit y avoir un formulaire intermédiaire.
La meilleure façon de procéder est d'utiliser le
Function
constructeur.Comme avec d'autres moteurs de modèles, vous pouvez obtenir cette chaîne à partir d'autres endroits, comme un fichier.
Il peut y avoir des problèmes en utilisant cette méthode, comme les balises de modèle sont difficiles à utiliser, mais celles-ci peuvent être ajoutées si vous êtes intelligent. Vous ne pouvez pas non plus avoir de logique JavaScript en ligne en raison de l'interpolation tardive. Cela peut également être corrigé avec une certaine réflexion.
la source
new Function(`return \`${template}\`;`)
Vous pouvez mettre une chaîne de modèle dans une fonction:
Vous pouvez faire la même chose avec un modèle balisé:
L'idée est de laisser l'analyseur de modèle séparer les chaînes constantes de la variable "slots", puis de renvoyer une fonction qui corrige le tout en fonction d'un nouvel ensemble de valeurs à chaque fois.
la source
reusable
pourrait être implémenté pour qu'il renvoie une fonction, et vous utiliseriez${0}
et${1}
à l'intérieur du littéral au lieu de${a}
et${b}
. Ensuite, vous pouvez utiliser ces valeurs pour faire référence aux arguments de la fonction, similaire à ce que fait Bergi dans son dernier exemple: stackoverflow.com/a/22619256/218196 (ou je suppose que c'est fondamentalement la même chose).expression`a + ${node}`
pour construire un nœud BinaryExpression avec un nœud AST existantnode
. En interne, nous insérons un espace réservé pour générer du code valide, l'analysons comme un AST et remplaçons l'espace réservé par la valeur transmise.Le moyen le plus propre de le faire est probablement d'utiliser les fonctions fléchées (car à ce stade, nous utilisons déjà ES6)
... Et pour les littéraux de gabarit balisés:
Cela évite également l'utilisation de
eval()
ouFunction()
qui peut causer des problèmes avec les compilateurs et causer beaucoup de ralentissements.la source
myTag
pour faire des choses. Par exemple, utilisez les paramètres d'entrée comme clé pour mettre en cache la sortie.var reusable = (value: string) => `Value is ${value}`
.Réponse de 2019 :
Remarque : la bibliothèque s'attendait à l'origine à ce que les utilisateurs nettoient les chaînes pour éviter XSS. La version 2 de la bibliothèque ne nécessite plus de nettoyer les chaînes utilisateur (ce que les développeurs Web devraient faire de toute façon) car cela évite
eval
complètement.Le
es6-dynamic-template
module sur npm le fait.Contrairement aux réponses actuelles:
this
dans la chaîne de modèleL'utilisation est simple. Utilisez des guillemets simples car la chaîne de modèle sera résolue plus tard!
la source
10 * 20 = ${10 * 20}
donc cela pourrait être un format similaire, mais ce n'est même pas à distance les littéraux de modèleOui, vous pouvez le faire en analysant votre chaîne avec le modèle en tant que JS par
Function
(oueval
) - mais ce n'est pas recommandé et autorise l' attaque XSSAfficher l'extrait de code
Au lieu de cela, vous pouvez insérer en toute sécurité des
obj
champs d' objet dans le modèlestr
de manière dynamique comme suitAfficher l'extrait de code
la source
.*?
moyen non gourmand - si vous supprimez, l'"?"
extrait donnera un résultat erronéfunction taggedTemplate(template, data, matcher) { if (!template || !data) { return template; } matcher = matcher || /{(\w*)}/g; // {one or more alphanumeric characters with no spaces} return template.replace(matcher, function (match, key) { var value; try { value = data[key] } catch (e) { // } return value || ""; }); }
data = { a: 1, b: { c:2, d:3 } }
->b.c
?Simplifier la réponse fournie par @metamorphasi;
la source
eval
.var hosting
) ICI .Si vous ne souhaitez pas utiliser les paramètres commandés ou le contexte / namespaces pour référencer les variables dans votre modèle, par exemple
${0}
,${this.something}
ou${data.something}
, vous pouvez avoir une fonction de modèle qui prend soin de la portée pour vous.Exemple de la façon dont vous pourriez appeler un tel modèle:
La fonction Template:
La bizarrerie dans ce cas est qu'il vous suffit de passer une fonction (dans l'exemple, j'ai utilisé une fonction de flèche) qui renvoie le littéral du modèle ES6. Je pense que c'est un compromis mineur pour obtenir le type d'interpolation réutilisable que nous recherchons.
Le voici sur GitHub: https://github.com/Adelphos/ES6-Reuseable-Template
la source
Object.values()
etObject.keys()
La réponse courte est simplement d'utiliser _.template dans lodash
la source
Peut - être que je manque quelque chose, car ma solution à ce problème me semble si évidente que je suis très surpris que personne n'ait déjà écrit cela dans une question aussi ancienne.
J'ai presque une seule ligne pour cela:
C'est tout. Lorsque je veux réutiliser un modèle et reporter la résolution des substitutions, je fais simplement:
L'application de cette balise renvoie un
'function'
(au lieu d'un'string'
) qui ignore tous les paramètres passés au littéral. Ensuite, il peut être appelé avec de nouveaux paramètres plus tard. Si un paramètre n'a pas de remplacement correspondant, il devient'undefined'
.Réponse étendue
Ce code simple est fonctionnel, mais si vous avez besoin d'un comportement plus élaboré, cette même logique peut être appliquée et les possibilités sont infinies. Vous pourriez:
Vous pouvez stocker les valeurs d'origine transmises au littéral dans la construction et les utiliser de manière créative lors de l'application du modèle. Ils peuvent devenir des indicateurs, des validateurs de type, des fonctions, etc. Voici un exemple qui les utilise comme valeurs par défaut:
Ensuite:
Faites-le en enveloppant cette logique dans une fonction qui attend, comme argument, une fonction personnalisée qui peut être appliquée dans la réduction (lors de la jonction des éléments du littéral de modèle) et retourne un nouveau modèle avec un comportement personnalisé.
Ensuite, vous pouvez, par exemple, écrire des modèles qui échappent ou nettoient automatiquement les paramètres lors de l'écriture html, css, sql, bash ...
Avec ce modèle SQL naïf (je le répète, naïf! ), Nous pourrions créer des requêtes comme celle-ci:
Acceptez les paramètres nommés pour la substitution: un exercice pas si difficile, basé sur ce qui a déjà été donné. Il y a une implémentation dans cette autre réponse .
Faites en sorte que l'objet de retour se comporte comme un
'string'
: Eh bien, c'est controversé, mais pourrait conduire à des résultats intéressants. Montré dans cette autre réponse .Résolvez les paramètres dans l'espace de noms global sur le site d'appel:
Eh bien, voici ce OP est montré son additif, en utilisant la commande
, je veux dire,evil
eval
. Cela pourrait être fait sanseval
, simplement en recherchant le nom de variable passé dans l'objet global (ou window). Je ne montrerai pas comment le faire car je ne l'aime pas. Les fermetures sont le bon choix.la source
C'est ma meilleure tentative:
Pour généraliser:
Si vous n'exécutez pas E6, vous pouvez également faire:
Cela semble être un peu plus concis que les réponses précédentes.
https://repl.it/@abalter/reusable-JS-template-literal
la source
En général, je suis contre l'utilisation du mal
eval()
, mais dans ce cas, cela a du sens:Ensuite, si vous modifiez les valeurs et appelez à nouveau eval (), vous obtenez le nouveau résultat:
Si vous le voulez dans une fonction, alors il peut être écrit comme ceci:
la source
eval
.eval()
explicitement est exactement la même chose queeval()
, par conséquent, cela ne présente aucun avantage car cela ne fait que rendre le code plus difficile à lire.populate
fonction ne construit pas dynamiquement le code, elle ne doit pas l'utilisereval
avec tous ses inconvénients.function populate(a,b) { return `${a}.${b}`; }
l'évaluation n'ajoute rienMISE À JOUR: La réponse suivante est limitée aux noms de variables uniques, donc, les modèles tels que:
'Result ${a+b}'
ne sont pas valides pour ce cas. Cependant, vous pouvez toujours jouer avec les valeurs du modèle:RÉPONSE ORIGINALE:
Basé sur les réponses précédentes mais créant une fonction utilitaire plus "conviviale":
Vous pouvez l'invoquer comme:
Et la chaîne résultante doit être:
la source
`Result: ${a+b}`
Si vous cherchez quelque chose d'assez simple (juste des champs variables fixes, pas de calculs, de conditionnels…) mais qui fonctionne aussi côté client sur les navigateurs sans support de chaîne de modèle comme IE 8,9,10,11 …
Et c'est parti:
la source
Je suis ennuyé de la redondance supplémentaire nécessaire de taper à
this.
chaque fois, donc j'ai aussi ajouté regex pour développer des variables comme.a
àthis.a
.Solution:
Utilisez comme tel:
la source
Je viens de publier un package npm qui peut simplement faire ce travail. Profondément inspiré par cette réponse .
Son outil est d'une simplicité mortelle. Je souhaite que vous l'aimiez.
la source
vous pouvez utiliser la fonction de flèche en ligne comme celle-ci, définition:
usage:
la source
Chaîne de modèle d'exécution
Tester
la source
la source