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 expletive
tidak dideklarasikan, itu menghasilkan sesuatu seperti My undefined template
. Super. Sebenarnya, di Chrome setidaknya, saya bahkan tidak dapat mendeklarasikan template; itu melempar kesalahan karena expletive
tidak 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.
<strike>
tag.Jawaban:
Untuk membuat literal ini berfungsi seperti mesin template lainnya, perlu ada formulir perantara.
Cara terbaik untuk melakukannya adalah dengan menggunakan
Function
konstruktor.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.
sumber
new Function(`return \`${template}\`;`)
Anda dapat meletakkan string template dalam sebuah fungsi:
Anda dapat melakukan hal yang sama dengan template yang diberi tag:
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.
sumber
reusable
bisa 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).expression`a + ${node}`
untuk membangun node BinaryExpression dengan node AST yang sudah adanode
. Secara internal kami memasukkan placeholder untuk menghasilkan kode yang valid, menguraikannya sebagai AST dan mengganti placeholder dengan nilai yang diteruskan.Mungkin cara terbersih untuk melakukan ini adalah dengan fungsi panah (karena pada titik ini, kami sudah menggunakan ES6)
... Dan untuk literal template yang diberi tag:
Ini juga menghindari penggunaan
eval()
atauFunction()
yang dapat menyebabkan masalah dengan kompiler dan menyebabkan banyak perlambatan.sumber
myTag
untuk melakukan beberapa hal. Misalnya, gunakan parameter input sebagai kunci untuk menyimpan output ke cache.var reusable = (value: string) => `Value is ${value}`
.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 menghindari
eval
sepenuhnya.The
es6-dynamic-template
modul NPM melakukan hal ini.Berbeda dengan jawaban saat ini:
this
dalam string templatePenggunaannya sederhana. Gunakan tanda kutip tunggal karena string template akan diselesaikan nanti!
sumber
10 * 20 = ${10 * 20}
jadi mungkin format yang serupa tetapi bahkan bukan literal template es6 jarak jauhYa, Anda dapat melakukannya dengan mem-parsing string Anda dengan template sebagai JS oleh
Function
(ataueval
) - tetapi ini tidak disarankan dan mengizinkan serangan XSSTampilkan cuplikan kode
Sebagai gantinya, Anda dapat dengan aman menyisipkan
obj
kolom objek ke templatestr
secara dinamis sebagai berikutTampilkan cuplikan kode
sumber
.*?
artinya tidak serakah - jika Anda menghapusnya"?"
maka cuplikan akan memberikan hasil yang salahfunction 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
?Sederhanakan jawaban yang diberikan oleh @metamorphasi;
sumber
eval
.var hosting
) DI SINI .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:
Fungsi Template:
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
sumber
Object.values()
danObject.keys()
Jawaban singkatnya cukup gunakan _.template di lodash
sumber
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:
Itu saja. Saat saya ingin menggunakan kembali template dan menunda resolusi substitusi, saya hanya melakukan:
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:
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:
Kemudian:
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.
Kemudian Anda dapat, misalnya, menulis template yang secara otomatis keluar atau membersihkan parameter saat menulis html, css, sql, bash ...
Dengan template sql naïve (saya ulangi, naïve! ) Ini kita dapat membuat query seperti ini:
Terima parameter bernama untuk substitusi: Latihan yang tidak terlalu sulit, berdasarkan apa yang sudah diberikan. Ada implementasi dalam jawaban lain ini .
Buat objek yang dikembalikan berperilaku seperti
'string'
: Ini kontroversial, tetapi dapat memberikan hasil yang menarik. Tampil dalam jawaban lain ini .Selesaikan parameter dalam namespace global di situs panggilan:
Nah, inilah yang OP tunjukkan adendumnya, pake perintah
maksud sayaevil
eval
,. Ini bisa dilakukan tanpaeval
, 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.sumber
Ini adalah usaha terbaik saya:
Untuk menggeneralisasi:
Jika Anda tidak menjalankan E6, Anda juga dapat melakukan:
Ini sepertinya sedikit lebih ringkas dari jawaban sebelumnya.
https://repl.it/@abalter/reusable-JS-template-literal
sumber
Secara umum saya menentang penggunaan kejahatan
eval()
, tetapi dalam hal ini masuk akal:Kemudian jika Anda mengubah nilai dan memanggil eval () lagi, Anda mendapatkan hasil baru:
Jika Anda menginginkannya dalam suatu fungsi, maka dapat ditulis seperti ini:
sumber
eval
.eval()
secara eksplisit sama persis denganeval()
, oleh karena itu tidak ada manfaatnya karena hanya membuat kode lebih sulit dibaca.populate
fungsi Anda tidak membangun kode secara dinamis, ia tidak boleh digunakaneval
dengan semua kekurangannya.function populate(a,b) { return `${a}.${b}`; }
eval menambahkan apaDIPERBARUI: 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:JAWABAN ASLI:
Berdasarkan jawaban sebelumnya tetapi membuat fungsi utilitas yang lebih "ramah":
Anda dapat menagihnya seperti:
Dan string yang dihasilkan harus:
sumber
`Result: ${a+b}`
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:
sumber
Saya kesal redundansi tambahan yang dibutuhkan mengetik
this.
setiap waktu, jadi saya juga menambahkan regex untuk memperluas variabel seperti.a
untukthis.a
.Larutan:
Gunakan seperti itu:
sumber
Saya hanya mempublikasikan satu paket npm yang dapat melakukan pekerjaan ini. Sangat terinspirasi oleh jawaban ini .
Penerapannya sangat sederhana. Berharap Anda akan menyukainya.
sumber
Anda dapat menggunakan fungsi panah sebaris seperti ini, definisi:
pemakaian:
sumber
String template runtime
Uji
sumber
sumber