Dapatkah literal template ES6 diganti saat runtime (atau digunakan kembali)?

129

tl; dr: Apakah mungkin membuat template literal yang dapat digunakan kembali?

Saya telah mencoba menggunakan template literal tetapi saya rasa saya tidak mengerti dan sekarang saya menjadi frustrasi. Maksud saya, saya pikir saya mengerti, tetapi "itu" seharusnya tidak bagaimana cara kerjanya, atau bagaimana seharusnya. Ini harus berbeda.

Semua contoh yang saya lihat (bahkan templat yang diberi tag) mengharuskan "penggantian" dilakukan pada waktu deklarasi dan bukan waktu berjalan, yang tampaknya sama sekali tidak berguna bagi saya untuk templat. Mungkin saya gila, tapi "template" bagi saya adalah dokumen yang berisi token yang dapat diganti saat Anda menggunakannya, bukan saat Anda membuatnya, selain itu hanya dokumen (mis., String). Template disimpan dengan token sebagai token & token tersebut dievaluasi ketika Anda ... mengevaluasinya.

Setiap orang mengutip contoh mengerikan yang mirip dengan:

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

Itu bagus, tapi jika saya sudah tahu a, saya akan return 'Worthless asd'atau return 'Worthless '+a. Apa gunanya? Sungguh. Oke, intinya adalah kemalasan; plus lebih sedikit, lebih mudah dibaca. Bagus. Tapi itu bukan template! Bukan IMHO. Dan MHO adalah yang terpenting! Masalahnya, IMHO, adalah template dievaluasi saat dideklarasikan, jadi, jika Anda melakukannya, IMHO:

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

Karena expletivetidak dideklarasikan, itu menghasilkan sesuatu seperti My undefined template. Super. Sebenarnya, di Chrome setidaknya, saya bahkan tidak dapat mendeklarasikan template; itu melempar kesalahan karena expletivetidak ditentukan. Yang saya butuhkan adalah dapat melakukan substitusi setelah mendeklarasikan template:

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

Namun saya tidak melihat bagaimana ini mungkin, karena ini bukan template sebenarnya. Bahkan ketika Anda mengatakan saya harus menggunakan tag, tidak, itu tidak berfungsi:

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

Ini semua telah membuat saya percaya bahwa literal template sangat salah nama dan harus disebut apa adanya: heredocs . Saya kira bagian "literal" seharusnya memberi tahu saya (seperti, tidak dapat diubah)?

Apakah saya melewatkan sesuatu? Adakah cara (yang baik) untuk membuat literal template yang dapat digunakan kembali?


Saya memberi Anda, literal template yang dapat digunakan kembali :

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

Dan inilah fungsi "penolong" yang naif ...

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

... untuk membuatnya "lebih baik".

Saya cenderung menyebutnya guterals template karena dari area mana mereka menghasilkan perasaan berkelok-kelok.

Josh
sumber
1
Itu mendukung coretan (tetapi tidak di komentar seperti ini). Letakkan teks Anda di <strike>tag.
Pointy
Literal template ES6 sebagian besar untuk interpolasi String kuno. Jika Anda ingin template dinamis gunakan Handlebars dll, atau solusi template bertanda Pointy.
bergabung
1
String template, terlepas dari namanya, tidak ada template . Lihat juga Tunda eksekusi untuk String Template ES6
Bergi
8
Bisakah Anda membuat posting Anda sedikit tidak terlalu kasar? Selain itu, sepertinya Anda bermaksud menulis tutorial dalam format Tanya Jawab, jika Anda melakukannya, hapus bagian " Saya memberi Anda… " dari pertanyaan Anda dan mempostingnya sebagai jawaban .
Bergi
Saya perhatikan ada banyak jawaban bagus di sini. Mungkin terima satu.
abalter

Jawaban:

86

Untuk membuat literal ini berfungsi seperti mesin template lainnya, perlu ada formulir perantara.

Cara terbaik untuk melakukannya adalah dengan menggunakan Functionkonstruktor.

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));

Seperti mesin template lainnya, Anda bisa mendapatkan string itu dari tempat lain seperti file.

Mungkin ada masalah menggunakan metode ini seperti tag template sulit digunakan, tetapi itu dapat ditambahkan jika Anda pintar. Anda juga tidak dapat memiliki logika JavaScript sebaris karena interpolasi yang terlambat. Ini juga bisa diatasi dengan beberapa pemikiran.

Quentin Engles
sumber
8
Bagus! Anda bahkan dapat menggunakannew Function(`return \`${template}\`;`)
Ruben Stolk
Dan template ini dapat disusun, atau "disertakan" melalui argumen dengan memanggil metode, atau meneruskan hasil kompilasi dari template lain.
Quentin Engles
Quentin apa artinya 'tanpa tag template'? Terima kasih!
mikemaccana
10
Berhati - hatilah karena template string ini agak 'tersembunyi' untuk transpilasi (yaitu webpack) dan TIDAK akan ditranspilasi menjadi sesuatu yang cukup kompatibel (yaitu IE11) di sisi klien ...!
Frank Nocke
9
Kerentanan XSS ? Detail di JSFIDDLE INI
Kamil Kiełczewski
65

Anda dapat meletakkan string template dalam sebuah fungsi:

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

Anda dapat melakukan hal yang sama dengan template yang diberi tag:

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"

Idenya adalah membiarkan parser template memisahkan string konstan dari variabel "slot", dan kemudian mengembalikan fungsi yang menambal semuanya kembali berdasarkan satu set nilai baru setiap saat.

Runcing
sumber
3
@FelixKling yang mungkin; Saya akan memeriksa dan memperbaikinya jika demikian. edit ya sepertinya saya meninggalkan bagian penting dari contoh, yang menjadi fungsi "dapat digunakan kembali" :)
Pointy
@FelixKling Saya tidak yakin apa yang harus saya lakukan karena saya sama sekali tidak dapat mengingat apa yang saya pikirkan saat itu!
Pointy
1
Ya, tidak masuk akal untuk menjadi tbh;) Anda selalu dapat menghapusnya .... tetapi reusablebisa diimplementasikan sehingga mengembalikan fungsi, dan Anda akan menggunakan ${0}dan ${1}di dalam literal, bukan ${a}dan ${b}. Kemudian Anda dapat menggunakan nilai tersebut untuk merujuk ke argumen fungsi, mirip dengan apa yang dilakukan Bergi di contoh terakhirnya: stackoverflow.com/a/22619256/218196 (atau saya rasa pada dasarnya sama).
Felix Kling
1
@FelixKling OK Saya pikir saya telah menemukan sesuatu yang setidaknya samar-samar sejalan dengan OP.
Pointy
3
Template yang diberi tag bisa sangat berguna jika hasilnya sebenarnya bukan string. Misalnya di salah satu proyek saya, saya menggunakannya untuk melakukan interpolasi node AST. Misalnya yang dapat dilakukan expression`a + ${node}`untuk membangun node BinaryExpression dengan node AST yang sudah ada node. Secara internal kami memasukkan placeholder untuk menghasilkan kode yang valid, menguraikannya sebagai AST dan mengganti placeholder dengan nilai yang diteruskan.
Felix Kling
45

Mungkin cara terbersih untuk melakukan ini adalah dengan fungsi panah (karena pada titik ini, kami sudah menggunakan 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"

... Dan untuk literal template yang diberi tag:

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"

Ini juga menghindari penggunaan eval()atau Function()yang dapat menyebabkan masalah dengan kompiler dan menyebabkan banyak perlambatan.

PilotInPyjamas
sumber
Saya pikir ini adalah yang terbaik karena Anda dapat memasukkan beberapa kode di dalam fungsi myTaguntuk melakukan beberapa hal. Misalnya, gunakan parameter input sebagai kunci untuk menyimpan output ke cache.
WOW
Saya rasa ini adalah jawaban terbaik. Anda juga dapat menambahkan parameter ke fungsi panah yang saya pikir membuatnya bahkan lebih bersih: var reusable = (value: string) => `Value is ${value}`.
haggisandchips
13

Jawaban 2019 :

Catatan : Pustaka awalnya mengharapkan pengguna untuk membersihkan string untuk menghindari XSS. Versi 2 pustaka tidak lagi membutuhkan string pengguna untuk dibersihkan (yang harus dilakukan oleh pengembang web) karena menghindarieval sepenuhnya.

The es6-dynamic-templatemodul NPM melakukan hal ini.

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

Berbeda dengan jawaban saat ini:

  • Ini menggunakan string template ES6, bukan format yang serupa. Memperbarui versi 2 menggunakan format yang serupa, bukan string template ES6, untuk mencegah pengguna menggunakan String masukan yang tidak dibersihkan.
  • Tidak perlu this dalam string template
  • Anda dapat menentukan string dan variabel template dalam satu fungsi
  • Ini adalah modul yang dipelihara dan dapat diperbarui, daripada copypasta dari StackOverflow

Penggunaannya sederhana. Gunakan tanda kutip tunggal karena string template akan diselesaikan nanti!

const greeting = fillTemplate('Hi ${firstName}', {firstName: 'Joe'});
mikemaccana
sumber
Jika Anda menggunakan ini dengan React Native, ini akan rusak khusus di Android. Waktu proses node Android tidak mendukung template dinamis, hanya template yang telah diisi sebelumnya
Oliver Dixon
1
Ini adalah solusi yang saya gunakan dalam proyek pribadi saya dan bekerja dengan sempurna. Saya sebenarnya berpikir itu ide yang buruk untuk menggunakan terlalu banyak pustaka terutama untuk utilitas kecil seperti ini.
Oliver Dixon
1
Kerentanan XSS ? Detail dalam FIDDLE INI
Kamil Kiełczewski
1
@kamil Hanya XSS jika Anda a) memberi pengguna kemampuan untuk membuat b) tidak membersihkan string input. Saya akan menambahkan peringatan bahwa orang harus membersihkan input pengguna.
mikemaccana
1
Ini tidak menggunakan literal template es6 dari jarak jauh. Coba 10 * 20 = ${10 * 20}jadi mungkin format yang serupa tetapi bahkan bukan literal template es6 jarak jauh
gman
12

Ya, Anda dapat melakukannya dengan mem-parsing string Anda dengan template sebagai JS oleh Function(atau eval) - tetapi ini tidak disarankan dan mengizinkan serangan XSS

Sebagai gantinya, Anda dapat dengan aman menyisipkan objkolom objek ke template strsecara dinamis sebagai berikut

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

Kamil Kiełczewski
sumber
Ini adalah metode yang saya gunakan dan berhasil dengan baik. Contoh yang baik! Apakah itu? setelah * dalam bantuan RegEx? Saya bukan ahli RegEx, tapi saya menebak karena * berarti nol atau lebih (dan Anda ingin "lebih" dalam kasus ini), tidak perlu pembatasan serakah?
Gen1-1
@ Gen1-1 itu .*? artinya tidak serakah - jika Anda menghapusnya "?"maka cuplikan akan memberikan hasil yang salah
Kamil Kiełczewski
Anda benar, kesalahan saya. Saya tidak menggunakan $ di template saya, dan menggunakan RegEx: / {(\ w *)} / g karena saya tidak pernah memiliki spasi di tag, tetapi. *? juga bekerja. Saya menggunakan: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 apakah ada juga data bersarang mungkin? seperti data = { a: 1, b: { c:2, d:3 } }-> b.c?
muescha
1
@muescha Anda akan mengubah baris: value = data [key], untuk menggunakan rekursi dan mencari seluruh objek data dan objek bersarang sampai Anda menemukan propertinya. Contoh: codereview.stackexchange.com/questions/73714/… , dan mikedoesweb.com/2016/es6-depth-first-object-tree-search
Gen1-1
9

Sederhanakan jawaban yang diberikan oleh @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);

subcoder
sumber
Kode ini lebih menjelaskan diri sendiri daripada jawaban terdepan. Mendapat suara saya :)
ymz
Ini akan memungkinkan Anda untuk menggunakan variabel atau file eksternal (dalam NodeJS) sebagai template atau secara dinamis membuatnya saat run-time. Tanpa menggunakan eval.
b01
Kerentanan XSS ? Bermain-main dengan kode berbahaya (variabel var hosting) DI SINI .
Kamil Kiełczewski
7

Jika Anda tidak ingin menggunakan parameter memerintahkan atau konteks / ruang nama untuk referensi variabel dalam template Anda, misalnya ${0}, ${this.something}atau ${data.something}, Anda dapat memiliki fungsi template yang mengurus scoping untuk Anda.

Contoh bagaimana Anda bisa memanggil template seperti itu:

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

Fungsi Template:

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);
  }
}

Kekhasan dalam kasus ini adalah Anda hanya perlu meneruskan fungsi (dalam contoh saya menggunakan fungsi panah) yang mengembalikan literal template ES6. Saya pikir itu adalah pengorbanan kecil untuk mendapatkan jenis interpolasi yang dapat digunakan kembali yang kita cari.

Ini dia di GitHub: https://github.com/Adelphos/ES6-Reuseable-Template

metamorfasi
sumber
3
Ini bagus, tetapi minifikasi (vals, func, dll) tidak diperlukan, 'cb' bukanlah callback (ini sepenuhnya adalah kode sinkronisasi), dan Anda dapat menggunakan Object.values()danObject.keys()
mikemaccana
3

Jawaban singkatnya cukup gunakan _.template di 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
sumber
3

Apakah saya melewatkan sesuatu? Adakah cara [bagus] untuk membuat template literal yang dapat digunakan kembali?

Mungkin saya melewatkan sesuatu, karena solusi saya untuk masalah ini tampak begitu jelas bagi saya sehingga saya sangat terkejut tidak ada yang menulis itu dalam pertanyaan lama.

Saya memiliki hampir satu baris untuk itu:

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

Itu saja. Saat saya ingin menggunakan kembali template dan menunda resolusi substitusi, saya hanya melakukan:

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

Menerapkan tag ini mengembalikan kembali a 'function'(bukan a 'string') yang mengabaikan parameter apa pun yang diteruskan ke literal. Kemudian bisa dipanggil dengan parameter baru nanti. Jika parameter tidak memiliki pengganti yang sesuai, itu menjadi 'undefined'.


Jawaban diperpanjang

Kode sederhana ini berfungsi, tetapi jika Anda membutuhkan perilaku yang lebih rumit, logika yang sama dapat diterapkan dan ada kemungkinan yang tidak terbatas. Anda bisa:

  1. Manfaatkan parameter asli:

Anda dapat menyimpan nilai asli yang diteruskan ke literal dalam konstruksi dan menggunakannya dalam cara yang kreatif saat menerapkan template. Mereka bisa menjadi flag, validator tipe, fungsi dll. Ini adalah contoh yang menggunakannya sebagai nilai default:

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

Kemudian:

    > t = deferWithDefaults`My template is: ${'extendable'} and ${'versatile'}`;
    > t('awesome');                 // 'My template is: awesome and versatile' 
  1. Tulis pabrik template:

Lakukan dengan membungkus logika ini dalam fungsi yang mengharapkan, sebagai argumen, fungsi kustom yang bisa diterapkan dalam pengurangan (saat menggabungkan potongan literal template) dan mengembalikan template baru dengan perilaku kustom.

    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);
    };

Kemudian Anda dapat, misalnya, menulis template yang secara otomatis keluar atau membersihkan parameter saat menulis 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);

Dengan template sql naïve (saya ulangi, naïve! ) Ini kita dapat membuat query seperti ini:

    > 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. Terima parameter bernama untuk substitusi: Latihan yang tidak terlalu sulit, berdasarkan apa yang sudah diberikan. Ada implementasi dalam jawaban lain ini .

  2. Buat objek yang dikembalikan berperilaku seperti 'string': Ini kontroversial, tetapi dapat memberikan hasil yang menarik. Tampil dalam jawaban lain ini .

  3. Selesaikan parameter dalam namespace global di situs panggilan:

Saya memberi Anda, literal template yang dapat digunakan kembali:

Nah, inilah yang OP tunjukkan adendumnya, pake perintah evilmaksud saya eval,. Ini bisa dilakukan tanpa eval, hanya dengan mencari nama variabel yang dilewatkan ke dalam objek global (atau jendela). Saya tidak akan menunjukkan bagaimana melakukannya karena saya tidak menyukainya. Closure adalah pilihan yang tepat.

Rodrigo Rodrigues
sumber
2

Ini adalah usaha terbaik saya:

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

Untuk menggeneralisasi:

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

Jika Anda tidak menjalankan E6, Anda juga dapat melakukan:

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

Ini sepertinya sedikit lebih ringkas dari jawaban sebelumnya.

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

abalter
sumber
2

Secara umum saya menentang penggunaan kejahatan eval(), tetapi dalam hal ini masuk akal:

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

console.log(populated);         // shows 1.2

Kemudian jika Anda mengubah nilai dan memanggil eval () lagi, Anda mendapatkan hasil baru:

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

console.log(populated);         // shows 3.4

Jika Anda menginginkannya dalam suatu fungsi, maka dapat ditulis seperti ini:

function populate(a, b){
  return `${a}.${b}`;
}
isapir
sumber
Jika Anda menulis fungsi yang mencakup template, Anda pasti tidak harus menggunakan eval.
Bergi
@Bergi Mengapa? Apa yang membedakannya dari penerapan Anda?
isapir
2
Alasan saya "sepertinya tahu" berlaku untuk kode yang dibuat secara dinamis. Menulis fungsi sehingga ia membangun hasil tanpa memanggil eval()secara eksplisit sama persis dengan eval(), oleh karena itu tidak ada manfaatnya karena hanya membuat kode lebih sulit dibaca.
isapir
1
Persis. Dan karena populatefungsi Anda tidak membangun kode secara dinamis, ia tidak boleh digunakan evaldengan semua kekurangannya.
Bergi
6
fungsi Anda hanya bisa menjadi function populate(a,b) { return `${a}.${b}`; }eval menambahkan apa
Vitim.us
1

DIPERBARUI: Jawaban berikut terbatas pada nama variabel tunggal, jadi, templat seperti: 'Result ${a+b}'tidak valid untuk kasus ini. Namun Anda selalu bisa bermain dengan nilai template:

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

JAWABAN ASLI:

Berdasarkan jawaban sebelumnya tetapi membuat fungsi utilitas yang lebih "ramah":

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

    return tpl_func.call(params);
}

Anda dapat menagihnya seperti:

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

Dan string yang dihasilkan harus:

'This is a test: Hola, second param: Hi'
Roberto
sumber
Bagaimana dengan template seperti ini? `Result: ${a+b}`
Atiris
1
Hai @Atiris, Anda benar, Itu batasan, saya telah memperbarui jawaban saya.
Roberto
1

Jika Anda mencari sesuatu yang agak sederhana (hanya bidang variabel tetap, tidak ada komputasi, bersyarat…) tetapi itu juga berfungsi di sisi klien pada browser tanpa dukungan string template seperti IE 8,9,10,11

Kita mulai:

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
sumber
Ini akan melakukan pencarian untuk setiap variabel. Ada cara lain yang menggantikan semua kejadian sekaligus yang saya terapkan dalam modul ini: safe-es6-template
Aalex Gabi
1

Saya kesal redundansi tambahan yang dibutuhkan mengetik this.setiap waktu, jadi saya juga menambahkan regex untuk memperluas variabel seperti .auntuk this.a.

Larutan:

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);

Gunakan seperti itu:

console.log(interp('Hello ${.a}${.b}')({ a: 'World', b: '!' }));
// outputs: Hello World!
NolePTR
sumber
1

Saya hanya mempublikasikan satu paket npm yang dapat melakukan pekerjaan ini. Sangat terinspirasi oleh jawaban ini .

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

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

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

Penerapannya sangat sederhana. Berharap Anda akan menyukainya.


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

  fill(data) {
    return this._func.call(data);
  }
}
zhoukekestar
sumber
1

Anda dapat menggunakan fungsi panah sebaris seperti ini, definisi:

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

pemakaian:

console.log(template('my replaced string'));
EladTal
sumber
1

String template runtime

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

Uji

console.debug(templateString('hello ${word} world', {word: 'wonderful'}));
Dennis T
sumber
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
sumber