Apakah mungkin membuat string template seperti string biasa
let a="b:${b}";
kemudian mengubahnya menjadi string template
let b=10;
console.log(a.template());//b:10
tanpa eval
, new Function
dan cara lain untuk menghasilkan kode dinamis?
javascript
ecmascript-6
eval
template-strings
KOLANICH
sumber
sumber
Jawaban:
Karena string template Anda harus mendapatkan referensi ke
b
variabel secara dinamis (dalam runtime), maka jawabannya adalah: TIDAK, itu tidak mungkin dilakukan tanpa pembuatan kode dinamis.Tetapi dengan
eval
itu cukup sederhana:sumber
a
tali dan itu akan jauh lebih sedikit tidak aman:let tpl = eval('`'+a.replace(/`/g,'\\`')+'`');
. Saya pikir yang lebih penting adalaheval
mencegah kompiler untuk mengoptimalkan kode Anda. Tapi saya pikir itu tidak relevan dengan pertanyaan ini.eval
. Namun, ingat bahwa templat literal itu sendiri adalah bentukeval
. Dua contoh: var test =Result: ${alert('hello')}
; var test =Result: ${b=4}
; Keduanya akan menjalankan kode arbitrer dalam konteks skrip. Jika Anda ingin mengizinkan string yang sewenang-wenang, Anda dapat juga mengizinkannyaeval
.Dalam proyek saya, saya telah membuat sesuatu seperti ini dengan ES6:
PEMBARUAN Saya telah menghapus ketergantungan lodash, ES6 memiliki metode yang setara untuk mendapatkan kunci dan nilai.
sumber
ReferenceError: _ is not defined
. Apakah kode itu bukan ES6 tetapilodash
spesifik, atau ...?Apa yang Anda minta di sini:
persis sama (dalam hal kekuatan dan, eh, keamanan) untuk
eval
: kemampuan untuk mengambil string yang berisi kode dan menjalankan kode itu; dan juga kemampuan kode yang dieksekusi untuk melihat variabel lokal di lingkungan pemanggil.Tidak ada cara di JS untuk fungsi untuk melihat variabel lokal di pemanggilnya, kecuali fungsi itu
eval()
. BahkanFunction()
tidak bisa melakukannya.Ketika Anda mendengar ada sesuatu yang disebut "string template" yang masuk ke JavaScript, wajar untuk menganggapnya sebagai pustaka template bawaan, seperti Moustache. Bukan itu. Ini terutama hanya interpolasi string dan string multiline untuk JS. Saya pikir ini akan menjadi kesalahpahaman umum untuk sementara waktu. :(
sumber
template is not a function
.Tidak, tidak ada cara untuk melakukan ini tanpa pembuatan kode dinamis.
Namun, saya telah membuat fungsi yang akan mengubah string biasa menjadi fungsi yang dapat disediakan dengan peta nilai, menggunakan string template secara internal.
Hasilkan Template String Gist
Pemakaian:
Semoga ini bisa membantu seseorang. Jika Anda menemukan masalah dengan kode, harap berbaik hati memperbarui Gist.
sumber
var test = generateTemplateString('/api/${param1}/${param2}/')
console.log(test({param1: 'bar', param2: 'foo'}))
dikembalikan/api/bar//
TLDR: https://jsfiddle.net/w3jx07vt/
Semua orang tampaknya khawatir tentang mengakses variabel, mengapa tidak lewat saja? Saya yakin itu tidak akan terlalu sulit untuk mendapatkan konteks variabel dalam penelepon dan meneruskannya. Gunakan ini https://stackoverflow.com/a/6394168/6563504 untuk mendapatkan alat peraga dari obj. Saya tidak dapat menguji untuk Anda sekarang, tetapi ini harus bekerja.
Diuji. Ini kode lengkapnya.
sumber
${}
karakter. Coba:/(?!\${)([^{}]*)(?=})/g
Masalahnya di sini adalah memiliki fungsi yang memiliki akses ke variabel pemanggilnya. Inilah mengapa kami melihat langsung
eval
digunakan untuk pemrosesan template. Solusi yang mungkin adalah menghasilkan fungsi yang mengambil parameter formal yang dinamai oleh properti kamus, dan memanggilnya dengan nilai yang sesuai dalam urutan yang sama. Cara alternatif adalah memiliki sesuatu yang sederhana seperti ini:Dan bagi siapa pun yang menggunakan kompiler Babel kita perlu membuat closure yang mengingat lingkungan di mana ia dibuat:
sumber
eval
karena hanya berfungsi denganname
variabel globalvar template = function() { var name = "John Smith"; var message = "Hello, my name is ${name}"; this.local = new Function('return
'+ message +';')();}
new Function
tidak memiliki akses kevar name
dalamtemplate
fungsi.Ada banyak solusi bagus yang diposting di sini, tetapi belum ada yang menggunakan metode String.raw ES6 . Ini contriubution saya. Ini memiliki batasan penting karena hanya akan menerima properti dari objek yang diteruskan, artinya tidak ada eksekusi kode dalam templat yang akan berfungsi.
parts: ["Hello, ", "! Are you ", " years old?"]
args: ["name", "age"]
obj
berdasarkan nama properti. Solusi dibatasi oleh pemetaan satu tingkat yang dangkal. Nilai yang tidak terdefinisi diganti dengan string kosong, tetapi nilai-nilai palsu lainnya diterima.parameters: ["John Doe", 18]
String.raw(...)
dan kembalikan hasil.sumber
.replace()
berulang kali?.replace()
, :) Saya pikir keterbacaan penting, jadi saat menggunakan ekspresi reguler sendiri, saya mencoba memberi nama mereka untuk membantu memahami semuanya ...Mirip dengan jawaban Daniel (dan inti s.meijer ) tetapi lebih mudah dibaca:
Catatan: Ini sedikit meningkatkan asli s.meijer, karena tidak akan cocok dengan hal-hal seperti
${foo{bar}
(regex hanya memungkinkan karakter penjepit non-keriting di dalam${
dan}
).UPDATE: Saya diminta untuk contoh menggunakan ini, jadi di sini Anda pergi:
sumber
/\$\{(.*?)(?!\$\{)\}/g
(untuk menangani kurung kurawal). Saya punya solusi yang berfungsi, tetapi saya tidak yakin ini se portable milik Anda, jadi saya ingin melihat bagaimana ini harus diterapkan dalam satu halaman. Milik saya juga menggunakaneval()
.eval
membuat Anda jauh lebih terbuka terhadap kemungkinan kesalahan yang akan menyebabkan masalah keamanan, sedangkan semua versi saya lakukan adalah mencari properti pada objek dari jalur yang dipisahkan titik, yang seharusnya aman.Anda dapat menggunakan prototipe string, misalnya
Tetapi jawaban dari pertanyaan awal tidak mungkin.
sumber
Saya menyukai jawaban s.meijer dan menulis versi saya sendiri berdasarkan pada:
sumber
Saya memerlukan metode ini dengan dukungan untuk Internet Explorer. Ternyata kutu belakang tidak didukung bahkan oleh IE11. Juga; menggunakan
eval
atau itu setaraFunction
rasanya tidak benar.Untuk yang memperhatikan; Saya juga menggunakan backticks, tetapi ini dihapus oleh kompiler seperti babel. Metode yang disarankan oleh yang lain, bergantung padanya pada run-time. Seperti dikatakan di atas; ini merupakan masalah di IE11 dan lebih rendah.
Jadi inilah yang saya pikirkan:
Contoh output:
sumber
eval('`' + taggedURL + '`')
tidak berhasil.eval
. Mengenai literal templat: terima kasih telah menunjukkannya lagi. Saya menggunakan Babel untuk mengubah kode saya tetapi fungsi saya tetap tidak berfungsi apparentlySaat ini saya tidak dapat mengomentari jawaban yang ada sehingga saya tidak dapat langsung mengomentari tanggapan luar biasa Bryan Raynor. Dengan demikian, respons ini akan memperbarui jawabannya dengan sedikit koreksi.
Singkatnya, fungsinya gagal untuk benar-benar men-cache fungsi yang dibuat, jadi itu akan selalu dibuat ulang, terlepas dari apakah itu melihat template sebelumnya. Berikut adalah kode yang diperbaiki:
sumber
@ Mosus Moska, solusi berfungsi dengan baik, tetapi ketika saya menggunakannya dalam React Native (build mode), ia melempar kesalahan: Karakter '' 'tidak valid , meskipun berfungsi ketika saya menjalankannya dalam mode debug.
Jadi saya menuliskan solusi saya sendiri menggunakan regex.
Demo: https://es6console.com/j31pqx1p/
CATATAN: Karena saya tidak tahu akar penyebab masalah, saya mengangkat tiket dalam repo asli-reaksi, https://github.com/facebook/react-native/issues/14107 , sehingga setelah itu mereka dapat memperbaiki / membimbing saya tentang hal yang sama :)
sumber
Masih dinamis tetapi tampaknya lebih terkontrol daripada hanya menggunakan eval telanjang:
https://repl.it/IdVt/3
sumber
Solusi ini bekerja tanpa ES6:
Catatan:
Function
konstruktor selalu dibuat dalam lingkup global, yang berpotensi menyebabkan variabel global ditimpa oleh templat, misalnyarender("hello ${ someGlobalVar = 'some new value' }", {name:'mo'});
sumber
Karena kita menciptakan kembali roda pada sesuatu yang akan menjadi fitur yang indah di javascript.
Saya menggunakan
eval()
, yang tidak aman, tetapi javascript tidak aman. Saya siap mengakui bahwa saya tidak hebat dengan javascript, tapi saya punya kebutuhan, dan saya butuh jawaban jadi saya membuatnya.Saya memilih untuk menyesuaikan dgn mode variabel saya dengan
@
, daripada karena$
, terutama karena saya ingin menggunakan fitur multiline dari literal tanpa mengevaluasi sampai siap. Jadi sintaks variabel adalah@{OptionalObject.OptionalObjectN.VARIABLE_NAME}
Saya bukan ahli javascript, jadi saya dengan senang hati menerima saran tentang peningkatan tetapi ...
Implementasi yang sangat sederhana berikut
Dalam implementasi saya yang sebenarnya, saya memilih untuk menggunakan
@{{variable}}
. Satu set kawat gigi lagi. Sangat tidak mungkin untuk menemukan itu secara tak terduga. Regex untuk itu akan terlihat seperti/\@\{\{(.*?)(?!\@\{\{)\}\}/g
Untuk membuatnya lebih mudah dibaca
Jika Anda tidak berpengalaman dengan regex, aturan yang cukup aman adalah melarikan diri dari setiap karakter non-alfanumerik, dan jangan pernah melarikan diri huruf secara sia-sia karena banyak huruf yang lolos memiliki makna khusus untuk hampir semua rasa regex.
sumber
Anda harus mencoba modul JS kecil ini, oleh Andrea Giammarchi, dari github: https://github.com/WebReflection/backtick-template
Demo (semua tes berikut menghasilkan true):
sumber
Saya membuat solusi saya sendiri melakukan suatu jenis dengan deskripsi sebagai fungsi
dan melakukan:
sumber
Alih-alih menggunakan eval lebih baik gunakan regex
Eval itu tidak direkomendasikan & sangat tidak disarankan, jadi tolong jangan menggunakannya ( mdn eval ).
sumber