Czy literały szablonów ES6 można zastąpić w czasie wykonywania (lub ponownie wykorzystać)?

129

tl; dr: Czy możliwe jest utworzenie literału szablonu wielokrotnego użytku?

Próbowałem użyć literałów szablonów, ale wydaje mi się, że po prostu tego nie rozumiem i teraz jestem sfrustrowany. To znaczy, myślę, że to rozumiem, ale „to” nie powinno być tym, jak to działa ani jak powinno. Powinno być inaczej.

Wszystkie przykłady, które widzę (nawet otagowane szablony) wymagają, aby „podstawienia” były wykonywane w czasie deklaracji, a nie w czasie wykonywania, co wydaje mi się całkowicie bezużyteczne dla szablonu. Może jestem szalony, ale „szablon” to dla mnie dokument, który zawiera tokeny, które są podstawiane, gdy go używasz, a nie kiedy go tworzysz, w przeciwnym razie jest to po prostu dokument (tj. Ciąg znaków). Szablon jest przechowywany z tokenami jako tokenami i te tokeny są oceniane, kiedy ... oceniasz go.

Wszyscy cytują okropny przykład podobny do:

var a = 'asd';
return `Worthless ${a}!`

To miłe, ale jeśli już wiem a, po prostu return 'Worthless asd'lub return 'Worthless '+a. Jaki jest sens? Poważnie. Dobra, chodzi o lenistwo; mniej plusów, większa czytelność. Wspaniały. Ale to nie jest szablon! Nie IMHO. A MHO to wszystko, co się liczy! Problem, IMHO, polega na tym, że szablon jest oceniany po zadeklarowaniu, więc jeśli to zrobisz, IMHO:

var tpl = `My ${expletive} template`;
function go() { return tpl; }
go(); // SPACE-TIME ENDS!

Ponieważ expletivenie jest zadeklarowany, wyświetla coś takiego My undefined template. Wspaniały. Właściwie przynajmniej w Chrome nie mogę nawet zadeklarować szablonu; zgłasza błąd, ponieważ expletivenie jest zdefiniowany. Potrzebuję tego, aby móc dokonać zamiany po zadeklarowaniu szablonu:

var tpl = `My ${expletive} template`;
function go() { return tpl; }
var expletive = 'great';
go(); // My great template

Jednak nie widzę, jak to jest możliwe, ponieważ tak naprawdę nie są to szablony. Nawet jeśli mówisz, że powinienem używać tagów, nie, nie działają:

> 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...

To wszystko doprowadziło mnie do przekonania, że ​​literały szablonów są strasznie błędnie nazwane i należy je nazwać tym, czym naprawdę są: heredocami . Wydaje mi się, że „dosłowna” część powinna mnie ostrzec (jak w, niezmienna)?

Czy coś mi brakuje? Czy istnieje (dobry) sposób na utworzenie literału szablonu wielokrotnego użytku?


Daję ci, wielokrotnego użytku literały szablonów :

> 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!

A oto naiwna funkcja „pomocnika” ...

function t(t) { return '`'+t.replace('{','${')+'`'; }
var template = t(`This is
my {expletive} reusable
template!`);

...zrobić to lepiej".

Jestem skłonny nazywać je szablonowymi guterałami ze względu na obszar, z którego wywołują zawirowania.

Josh
źródło
1
Obsługuje przekreślenie (ale nie w komentarzach takich jak ten). Umieść swój tekst w <strike>tagu.
Pointy
Literały szablonów ES6 są głównie przeznaczone do staromodnej interpolacji ciągów. Jeśli chcesz korzystać z szablonów dynamicznych, użyj uchwytów itp., Lub rozwiązania szablonów ze znacznikami Pointy.
joews
1
Ciągi szablonów, pomimo nazwy, nie zawierają szablonów . Zobacz także Odroczenie wykonania dla ciągów szablonów ES6
Bergi
8
Czy możesz sprawić, by Twój post był nieco mniej ranny? Wygląda na to, że zamierzałeś napisać samouczek w formacie pytań i odpowiedzi . Jeśli to zrobiłeś, usuń część „ Daję ci… ” z pytania i opublikuj ją jako odpowiedź .
Bergi
Zauważyłem, że jest tu wiele dobrych odpowiedzi. Może zaakceptuj jedną.
abalter

Odpowiedzi:

86

Aby te literały działały jak inne silniki szablonów, potrzebny jest formularz pośredni.

Najlepszym sposobem na to jest użycie Functionkonstruktora.

const templateString = "Hello ${this.name}!";
const templateVars = {
    name: "world"    
}

const fillTemplate = function(templateString, templateVars){
    return new Function("return `"+templateString +"`;").call(templateVars);
}

console.log(fillTemplate(templateString, templateVars));

Podobnie jak w przypadku innych silników szablonów, możesz pobrać ten ciąg z innych miejsc, takich jak plik.

Podczas korzystania z tej metody mogą wystąpić problemy, na przykład tagi szablonów są trudne w użyciu, ale można je dodać, jeśli jesteś sprytny. Nie możesz również mieć wbudowanej logiki JavaScript z powodu późnej interpolacji. Można temu zaradzić, myśląc.

Quentin Engles
źródło
8
Miły! Możesz nawet użyćnew Function(`return \`${template}\`;`)
Ruben Stolk
Te szablony mogą być składane lub „dołączane” za pomocą argumentów przez wywołanie metody lub przekazanie skompilowanego wyniku innego szablonu.
Quentin Engles
Quentin, co oznacza „brak tagów szablonów”? Dzięki!
mikemaccana
10
uważaj , ten ciąg szablonu jest w pewnym sensie „ukryty” do transpilacji (tj. webpacka) i dlatego NIE zostanie transponowany na coś wystarczająco kompatybilnego (np. IE11) po stronie klienta ...!
Frank Nocke
9
Luka w zabezpieczeniach XSS ? Szczegóły w TYM JSFIDDLE
Kamil Kiełczewski
65

Możesz umieścić ciąg szablonu w funkcji:

function reusable(a, b) {
  return `a is ${a} and b is ${b}`;
}

Możesz zrobić to samo z otagowanym szablonem:

function reusable(strings) {
  return function(... vals) {
    return strings.map(function(s, i) {
      return `${s}${vals[i] || ""}`;
    }).join("");
  };
}

var tagged = reusable`a is ${0} and b is ${1}`; // dummy "parameters"
console.log(tagged("hello", "world"));
// prints "a is hello b is world"
console.log(tagged("mars", "jupiter"));
// prints "a is mars b is jupiter"

Pomysł polega na tym, aby pozwolić parserowi szablonu oddzielić ciągi stałe od zmiennej „slots”, a następnie zwrócić funkcję, która za każdym razem łączy je z powrotem w oparciu o nowy zestaw wartości.

Spiczasty
źródło
3
@FelixKling to może być; Sprawdzę i naprawię, jeśli tak. edytuj tak, wygląda na to, że pominąłem znaczną część przykładu, który jest funkcją „wielokrotnego użytku” :)
Pointy
@FelixKling Nie jestem pewien, co robić, ponieważ w ogóle nie mogę sobie przypomnieć, o czym wtedy myślałem!
Pointy
1
Tak, nie ma sensu być albo tbh;) Zawsze możesz go usunąć ... ale reusablemożna by go zaimplementować, aby zwracał funkcję i używałbyś ${0}i ${1}wewnątrz literału zamiast ${a}i ${b}. Następnie możesz użyć tych wartości, aby odwołać się do argumentów funkcji, podobnie do tego, co robi Bergi w swoim ostatnim przykładzie: stackoverflow.com/a/22619256/218196 (lub wydaje mi się, że to w zasadzie to samo).
Felix Kling
1
@FelixKling OK. Myślę, że wymyśliłem coś, co jest przynajmniej niejasno podobne do OP.
Pointy
3
Otagowane szablony mogą być naprawdę potężne, jeśli wynikiem w rzeczywistości nie jest ciąg. Na przykład w jednym z moich projektów używam go do interpolacji węzłów AST. Np. Można expression`a + ${node}`zbudować węzeł BinaryExpression z istniejącym węzłem AST node. Wewnętrznie wstawiamy symbol zastępczy, aby wygenerować prawidłowy kod, analizujemy go jako AST i zastępujemy symbol zastępczy przekazaną wartością.
Felix Kling
45

Prawdopodobnie najczystszym sposobem na to są funkcje strzałkowe (ponieważ w tym momencie używamy już ES6)

var reusable = () => `This ${object} was created by ${creator}`;

var object = "template string", creator = "a function";
console.log (reusable()); // "This template string was created by a function"

object = "example", creator = "me";
console.log (reusable()); // "This example was created by me"

... a dla otagowanych literałów szablonów:

reusable = () => myTag`The ${noun} go ${verb} and `;

var noun = "wheels on the bus", verb = "round";
var myTag = function (strings, noun, verb) {
    return strings[0] + noun + strings[1] + verb + strings[2] + verb;
};
console.log (reusable()); // "The wheels on the bus go round and round"

noun = "racecars", verb = "fast";
myTag = function (strings, noun, verb) {
    return strings[0] + noun + strings[1] + verb;
};
console.log (reusable()); // "The racecars go fast"

Pozwala to również uniknąć użycia eval()lub Function()może powodować problemy z kompilatorami i powodować spowolnienie.

PilotInPyjamas
źródło
Myślę, że jest to jeden z najlepszych, ponieważ możesz wprowadzić kilka kodów do funkcji, myTagaby zrobić coś. Na przykład użyj parametrów wejściowych jako klucza do buforowania danych wyjściowych.
WOW,
Myślę, że to najlepsza odpowiedź. Można też dodać parametry do funkcji strzałką co moim zdaniem sprawia, że nawet czystsze: var reusable = (value: string) => `Value is ${value}`.
haggisandchips
13

Odpowiedź 2019 :

Uwaga : biblioteka początkowo oczekiwała, że ​​użytkownicy będą oczyszczać ciągi znaków, aby uniknąć XSS. Wersja 2 biblioteki nie wymaga już czyszczenia ciągów użytkownika (co i tak powinni zrobić twórcy stron internetowych), ponieważ evalcałkowicie unika .

es6-dynamic-templateModuł na KMP to robi.

const fillTemplate = require('es6-dynamic-template');

W przeciwieństwie do obecnych odpowiedzi:

  • Używa ciągów szablonów ES6, a nie podobnego formatu. Aktualizacja w wersji 2 używa podobnego formatu zamiast ciągów szablonów ES6, aby uniemożliwić użytkownikom korzystanie z niezanieczyszczonych ciągów wejściowych.
  • Nie ma potrzeby thisw ciągu szablonu
  • Możesz określić ciąg szablonu i zmienne w jednej funkcji
  • Jest to utrzymywany, aktualizowalny moduł, a nie copypasta ze StackOverflow

Użycie jest proste. Użyj pojedynczych cudzysłowów, ponieważ ciąg szablonu zostanie rozwiązany później!

const greeting = fillTemplate('Hi ${firstName}', {firstName: 'Joe'});
mikemaccana
źródło
Jeśli używasz tego z React Native, zepsuje się specjalnie na Androidzie. Środowisko uruchomieniowe węzła Androida nie obsługuje szablonów dynamicznych, tylko wstępnie wypełnione
Oliver Dixon
1
To rozwiązanie, z którego korzystam w swoich osobistych projektach i działa bez zarzutu. Właściwie uważam, że używanie zbyt wielu bibliotek, szczególnie w przypadku takich małych narzędzi, jest złym pomysłem.
Oliver Dixon
1
Luka w zabezpieczeniach XSS ? Szczegóły w THIS FIDDLE
Kamil Kiełczewski
1
@kamil Tylko XSS, jeśli a) dajesz użytkownikom możliwość tworzenia b) nie oczyszczaj ciągów wejściowych. Dodam jednak ostrzeżenie, że ludzie powinni oczyszczać dane wejściowe użytkownika.
mikemaccana
1
To nie zdalnie używa literałów szablonu es6. Spróbuj 10 * 20 = ${10 * 20}, może to być podobny format, ale nie jest to nawet zdalnie literały szablonu es6
gman
12

Tak, możesz to zrobić, analizując swój ciąg z szablonem jako JS przez Function(lub eval) - ale nie jest to zalecane i zezwalaj na atak XSS

Zamiast tego możesz bezpiecznie wstawiać objpola obiektów do szablonu strw sposób dynamiczny w następujący sposób

let inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);

Kamil Kiełczewski
źródło
To jest metoda, której używam i działa dobrze. Dobry przykład! Czy? po * w pomocy RegEx? Nie jestem ekspertem od RegEx, ale zgaduję, że skoro * oznacza zero lub więcej (a chcesz w tym przypadku „więcej”), nie ma potrzeby stosowania chciwego ograniczenia?
Gen1-1
@ Gen1-1 .*?oznacza nie chciwy - jeśli usuniesz "?"to snippet da zły wynik
Kamil Kiełczewski
Masz rację, mój błąd. Nie używam znaku $ w moich szablonach i używam RegEx: / {(\ w *)} / g, ponieważ nigdy nie mam spacji w tagu, ale. *? też działa. Używam: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 || ""; }); }
Gen1-1
@ Gen1-1 czy możliwe są również dane zagnieżdżone? jak data = { a: 1, b: { c:2, d:3 } }-> b.c?
muescha
1
@muescha Zmieniłbyś wiersz: wartość = dane [klucz], aby użyć rekursji i przeszukać cały obiekt danych i obiekty zagnieżdżone, aż znajdziesz właściwość. Przykłady: codereview.stackexchange.com/questions/73714/… i mikedoesweb.com/2016/es6-depth-first-object-tree-search
Gen1-1
9

Upraszczanie odpowiedzi udzielonej przez @metamorphasi;

const fillTemplate = function(templateString, templateVars){
  var func = new Function(...Object.keys(templateVars),  "return `"+templateString +"`;")
  return func(...Object.values(templateVars));
}

// Sample
var hosting = "overview/id/d:${Id}";
var domain = {Id:1234, User:22};
var result = fillTemplate(hosting, domain);

console.log(result);

subkoder
źródło
Ten kod jest bardziej zrozumiały niż wiodąca odpowiedź. Mam
pozytywny
Powinno to umożliwić używanie zmiennych lub plików zewnętrznych (w NodeJS) jako szablonów lub dynamiczne tworzenie ich w czasie wykonywania. Bez użycia eval.
b01
Luka w zabezpieczeniach XSS ? Baw się złośliwym kodem (zmienną var hosting) TUTAJ .
Kamil Kiełczewski
7

Jeśli nie chcesz korzystać z zamówionych parametrów lub kontekstu / nazw odwołać się do zmiennych w szablonie, na przykład ${0}, ${this.something}lub${data.something} można mieć funkcję szablonu, który dba o tworzenie zakresów dla Ciebie.

Przykład, jak można nazwać taki szablon:

const tempGreet = Template(() => `
  <span>Hello, ${name}!</span>
`);
tempGreet({name: 'Brian'}); // returns "<span>Hello, Brian!</span>"

Funkcja szablonu:

function Template(cb) {
  return function(data) {
    const dataKeys = [];
    const dataVals = [];
    for (let key in data) {
      dataKeys.push(key);
      dataVals.push(data[key]);
    }
    let func = new Function(...dataKeys, 'return (' + cb + ')();');
    return func(...dataVals);
  }
}

Dziwactwo w tym przypadku polega na tym, że wystarczy przekazać funkcję (w przykładzie użyłem funkcji strzałki), która zwraca literał szablonu ES6. Myślę, że to drobny kompromis, aby uzyskać taką interpolację wielokrotnego użytku, której szukamy.

Tutaj jest na GitHub: https://github.com/Adelphos/ES6-Reuseable-Template

metamorphasi
źródło
3
To dobrze, ale minifikacja (vals, func itp.) Jest niepotrzebna, „cb” nie jest wywołaniem zwrotnym (jest to całkowicie kod synchronizacji) i możesz po prostu użyć Object.values()iObject.keys()
mikemaccana.
3

Krótka odpowiedź brzmi: użyj _.template w lodash

// Use the ES template literal delimiter as an "interpolate" delimiter.
// Disable support by replacing the "interpolate" delimiter.
var compiled = _.template('hello ${ user }!');
compiled({ 'user': 'pebbles' });
// => 'hello pebbles!'
aGuegu
źródło
3

Czy coś mi brakuje? Czy istnieje [dobry] sposób na utworzenie literału szablonu wielokrotnego użytku?

Może czegoś mi brakuje, bo moje rozwiązanie tego problemu wydaje mi się tak oczywiste, że jestem bardzo zaskoczony, że nikt nie napisał tego już w tak starym pytaniu.

Mam na to prawie jedną linijkę:

function defer([first, ...rest]) {
  return (...values) => rest.reduce((acc, str, i) => acc + values[i] + str, first);
}

To wszystko. Kiedy chcę ponownie użyć szablonu i odroczyć rozstrzygnięcie podstawień, po prostu robię:

> t = defer`My template is: ${null} and ${null}`;
> t('simple', 'reusable');          // 'My template is: simple and reusable'
> t('obvious', 'late to the party'; // 'My template is: obvious and late to the party'
> t(null);                          // 'My template is: null and undefined'
>
> defer`Choose: ${'ignore'} / ${undefined}`(true, false); // 'Choose: true / false'

Zastosowanie tego tagu zwraca z powrotem a 'function'(zamiast a 'string'), który ignoruje wszelkie parametry przekazane do literału. Następnie można go później wywołać z nowymi parametrami. Jeśli parametr nie ma odpowiedniego zastąpienia, staje się 'undefined'.


Rozszerzona odpowiedź

Ten prosty kod jest funkcjonalny, ale jeśli potrzebujesz bardziej rozbudowanego zachowania, możesz zastosować tę samą logikę i masz nieskończone możliwości. Mógłbyś:

  1. Skorzystaj z oryginalnych parametrów:

Możesz przechowywać oryginalne wartości przekazane do literału w konstrukcji i używać ich w kreatywny sposób podczas stosowania szablonu. Mogą stać się flagami, walidatorami typów, funkcjami itp. Oto przykład, w którym są używane jako wartości domyślne:

    function deferWithDefaults([first, ...rest], ...defaults) {
      return (...values) => rest.reduce((acc, curr, i) => {
        return acc + (i < values.length ? values[i] : defaults[i]) + curr;
      }, first);
    }

Następnie:

    > t = deferWithDefaults`My template is: ${'extendable'} and ${'versatile'}`;
    > t('awesome');                 // 'My template is: awesome and versatile' 
  1. Napisz fabrykę szablonów:

Zrób to, opakowując tę ​​logikę w funkcję, która oczekuje jako argument funkcji niestandardowej, którą można zastosować w redukcji (podczas łączenia fragmentów literału szablonu) i zwraca nowy szablon z niestandardowym zachowaniem.

    const createTemplate = fn => function (strings, ...defaults) {
      const [first, ...rest] = strings;
      return (...values) => rest.reduce((acc, curr, i) => {
        return acc + fn(values[i], defaults[i]) + curr;
      }, first);
    };

Wtedy możesz np. Napisać szablony, które automatycznie zmieniają wartość lub oczyszczają parametry podczas pisania osadzonego html, css, sql, bash ...

    function sqlSanitize(token, tag) {
      // this is a gross simplification, don't use in production.
      const quoteName = name => (!/^[a-z_][a-z0-9_$]*$/.test(name) ? `"${name.replace(/"/g, '""')}"` : name);
      const quoteValue = value => (typeof value == 'string' ? `'${value.replace(/'/g, "''")}'` : value);
      switch (tag) {
        case 'table':
          return quoteName(token);
        case 'columns':
          return token.map(quoteName);
        case 'row':
          return token.map(quoteValue);
        default:
          return token;
      }
    }

    const sql = createTemplate(sqlSanitize);

Za pomocą tego naiwnego (powtarzam, naiwnego! ) Szablonu sql możemy budować takie zapytania:

    > q  = sql`INSERT INTO ${'table'} (${'columns'})
    ... VALUES (${'row'});`
    > q('user', ['id', 'user name', 'is"Staff"?'], [1, "O'neil", true])
    // `INSERT INTO user (id,"user name","is""Staff""?")
    // VALUES (1,'O''neil',true);`
  1. Zaakceptuj nazwane parametry do zastąpienia: Niezbyt trudne ćwiczenie oparte na tym, co zostało już podane. W tej innej odpowiedzi jest implementacja .

  2. Spraw, aby zwracany obiekt zachowywał się jak 'string': Cóż, jest to kontrowersyjne, ale może prowadzić do interesujących wyników. Pokazane w tej innej odpowiedzi .

  3. Rozwiązywanie parametrów w globalnej przestrzeni nazw w miejscu wywołania:

Daję ci, wielokrotnego użytku literały szablonów:

Cóż, to co pokazał OP jest jego uzupełnienie, używając polecenia evil, to znaczy eval. Można to zrobić bez eval, po prostu przeszukując przekazaną nazwę zmiennej do obiektu globalnego (lub okna). Nie pokażę, jak to zrobić, bo mi się to nie podoba. Zamknięcia to właściwy wybór.

Rodrigo Rodrigues
źródło
2

To moja najlepsza próba:

var s = (item, price) => {return `item: ${item}, price: $${price}`}
s('pants', 10) // 'item: pants, price: $10'
s('shirts', 15) // 'item: shirts, price: $15'

Aby uogólnić:

var s = (<variable names you want>) => {return `<template with those variables>`}

Jeśli nie używasz E6, możesz również wykonać:

var s = function(<variable names you want>){return `<template with those variables>`}

Wydaje się, że jest to nieco bardziej zwięzłe niż poprzednie odpowiedzi.

https://repl.it/@abalter/reusable-JS-template-literal

abalter
źródło
2

Generalnie jestem przeciwny używaniu zła eval(), ale w tym przypadku ma to sens:

var template = "`${a}.${b}`";
var a = 1, b = 2;
var populated = eval(template);

console.log(populated);         // shows 1.2

Następnie, jeśli zmienisz wartości i ponownie wywołasz eval (), otrzymasz nowy wynik:

a = 3; b = 4;
populated = eval(template);

console.log(populated);         // shows 3.4

Jeśli chcesz to w funkcji, możesz to zapisać w następujący sposób:

function populate(a, b){
  return `${a}.${b}`;
}
isapir
źródło
Jeśli piszesz funkcję, która zawiera szablon, zdecydowanie nie powinieneś jej używać eval.
Bergi,
@Bergi Why? Czym różni się od Twojej realizacji?
isapir
2
Powody, dla których „wydaje mi się, że wiem” odnoszą się do każdego dynamicznie budowanego kodu. Pisanie funkcji tak, aby budowała wynik bez eval()jawnego wywoływania, jest dokładnie tym samym, co eval(), dlatego nie ma z tego żadnej korzyści, ponieważ utrudnia tylko odczytanie kodu.
isapir,
1
Dokładnie. A ponieważ twoja populatefunkcja nie buduje dynamicznie kodu, nie powinna używać evalwszystkich swoich wad.
Bergi,
6
Twoja funkcja mogłaby być po prostu function populate(a,b) { return `${a}.${b}`; }eval, nic nie dodaje
Vitim.us
1

AKTUALIZACJA: Poniższa odpowiedź jest ograniczona do nazw pojedynczych zmiennych, więc szablony takie jak: 'Result ${a+b}'nie są poprawne w tym przypadku. Zawsze możesz jednak pobawić się wartościami szablonu:

format("This is a test: ${a_b}", {a_b: a+b});

ORYGINALNA ODPOWIEDŹ:

Oparta na poprzednich odpowiedziach, ale tworząca bardziej „przyjazną” funkcję użytkową:

var format = (template, params) => {
    let tpl = template.replace(/\${(?!this\.)/g, "${this.");
    let tpl_func = new Function(`return \`${tpl}\``);

    return tpl_func.call(params);
}

Możesz to wywołać tak jak:

format("This is a test: ${hola}, second param: ${hello}", {hola: 'Hola', hello: 'Hi'});

Wynikowy ciąg powinien być:

'This is a test: Hola, second param: Hi'
Roberto
źródło
A co z takim szablonem? `Result: ${a+b}`
Atiris
1
Cześć @Atiris, masz rację, to jest ograniczenie, zaktualizowałem moją odpowiedź.
Roberto
1

Jeśli szukasz czegoś raczej prostego (tylko stałe pola zmiennych, bez obliczeń, warunków…), ale działa to również po stronie klienta w przeglądarkach bez obsługi ciągów szablonów, takich jak IE 8,9,10,11

No to ruszamy:

fillTemplate = function (templateString, templateVars) {
    var parsed = templateString;
    Object.keys(templateVars).forEach(
        (key) => {
            const value = templateVars[key]
            parsed = parsed.replace('${'+key+'}',value)
        }
    )
    return parsed
}
Frank Nocke
źródło
Spowoduje to wyszukanie każdej zmiennej. Jest inny sposób, który zastępuje wszystkie zdarzenia naraz, które zaimplementowałem w tym module: safe-es6-template
Aalex Gabi
1

Byłem zły na dodatkowej redundancji potrzebna wpisywać this.za każdym razem, więc ja również dodaje regex aby rozwinąć zmiennych jak .ado this.a.

Rozwiązanie:

const interp = template => _thisObj =>
function() {
    return template.replace(/\${([^}]*)}/g, (_, k) =>
        eval(
            k.replace(/([.a-zA-Z0-9$_]*)([a-zA-Z0-9$_]+)/, (r, ...args) =>
                args[0].charAt(0) == '.' ? 'this' + args[0] + args[1] : r
            )
        )
    );
}.call(_thisObj);

Użyj jako takiego:

console.log(interp('Hello ${.a}${.b}')({ a: 'World', b: '!' }));
// outputs: Hello World!
NolePTR
źródło
1

Po prostu publikuję jeden pakiet npm, który może po prostu wykonać tę pracę. Głęboko zainspirowany tą odpowiedzią .

const Template = require('dynamic-template-string');

var tpl = new Template('hello ${name}');

tpl.fill({name: 'world'}); // ==> 'hello world';
tpl.fill({name: 'china'}); // ==> 'hello china';

Jego narzędzie jest zabójczo proste. Szkoda, że ​​ci się to nie spodoba.


module.exports = class Template {
  constructor(str) {
    this._func = new Function(`with(this) { return \`${str}\`; }`);
  }

  fill(data) {
    return this._func.call(data);
  }
}
zhoukekestar
źródło
1

możesz użyć funkcji strzałki wbudowanej w ten sposób, definicja:

const template = (substitute: string) => `[^.?!]*(?<=[.?\s!])${substitute}(?=[\s.?!])[^.?!]*[.?!]`;

stosowanie:

console.log(template('my replaced string'));
EladTal
źródło
1

Ciąg szablonu środowiska uruchomieniowego

var templateString = (template, values) => {
    let output = template;
    Object.keys(values)
        .forEach(key => {
        output = output.replace(new RegExp('\\$' + `{${key}}`, 'g'), values[key]);
    });
    return output;
};

Test

console.debug(templateString('hello ${word} world', {word: 'wonderful'}));
Dennis T
źródło
0

const fillTemplate = (template, values) => {
  template = template.replace(/(?<=\${)\w+(?=})/g, v=>"this."+v);
  return Function.apply(this, ["", "return `"+template+"`;"]).call(values);
};

console.log(fillTemplate("The man ${man} is brother of ${brother}", {man: "John", brother:"Peter"}));
//The man John is brother of Peter

Raul
źródło