Rumah >hujung hadapan web >tutorial js >Penjelasan terperinci tentang rentetan templat dalam pengetahuan JavaScript ES6_Basic
Jenis literal rentetan baharu diperkenalkan dalam ES6 - rentetan templat Kecuali untuk penggunaan tanda belakang (`), ia kelihatan sama dengan rentetan biasa. Dalam kes paling mudah, ia hanyalah rentetan biasa:
context.fillText(`Ceci n'est pas une cha?ne.`, x, y); context.fillText(`Ceci n'est pas une cha?ne.`, x, y);
dipanggil rentetan templat kerana rentetan templat memperkenalkan ciri interpolasi rentetan ringkas kepada JS, iaitu nilai JS boleh dimasukkan dengan mudah dan elegan ke dalam rentetan.
Rentetan templat boleh digunakan di banyak tempat, lihat mesej ralat yang tidak ketara berikut:
function authorize(user, action) { if (!user.hasPrivilege(action)) { throw new Error( `User ${user.name} is not authorized to do ${action}.`); } } function authorize(user, action) { if (!user.hasPrivilege(action)) { throw new Error( `User ${user.name} is not authorized to do ${action}.`); } }
Dalam kod di atas, ${user.name} dan ${action} dipanggil pemegang tempat templat JavaScript akan memasukkan nilai nama pengguna dan tindakan masing-masing ke dalam kedudukan yang sepadan, dan kemudian menjana "Pengguna. "Seperti ini jorendorff tidak dibenarkan melakukan hoki."
Sekarang kami mempunyai sintaks yang lebih elegan daripada pengendali, berikut ialah beberapa ciri yang boleh anda jangkakan:
Pemegang tempat templat boleh menjadi sebarang ungkapan JavaScript, jadi panggilan fungsi dan empat operasi aritmetik adalah sah. (Anda juga boleh menyusun rentetan templat dalam rentetan templat lain.)
Jika nilai bukan rentetan, ia akan ditukar kepada rentetan. Contohnya, jika tindakan ialah objek, maka .toString() objek itu akan dipanggil untuk menukarnya kepada rentetan.
Jika anda ingin menggunakan kutu belakang dalam rentetan templat, anda perlu melepaskannya dengan garis miring ke belakang.
Begitu juga, jika anda ingin mengeluarkan ${ dalam rentetan templat, anda juga perlu menggunakan garis miring ke belakang untuk melepaskannya: ${ atau ${.
Rentetan templat boleh menjangkau berbilang baris:
$("#warning").html(` <h1>Watch out!</h1> <p>Unauthorized hockeying can result in penalties of up to ${maxPenalty} minutes.</p> `); $("#warning").html(` <h1>Watch out!</h1> <p>Unauthorized hockeying can result in penalties of up to ${maxPenalty} minutes.</p> `);
Semua ruang, baris baharu dan inden dalam rentetan templat akan dikeluarkan kepada rentetan hasil sebagaimana adanya.
Mari kita lihat perkara yang tidak boleh dilakukan oleh rentetan templat:
Watak istimewa tidak akan terlepas secara automatik Untuk mengelakkan kerentanan skrip merentas tapak, anda masih perlu berhati-hati dengan data yang tidak dipercayai, sama seperti rentetan biasa.
Ia tidak boleh digunakan dengan perpustakaan antarabangsa dan tidak mengendalikan nombor, tarikh, dsb. dalam format bahasa khas.
Bukan pengganti untuk enjin templat (seperti Mustache atau Nunjucks). Rentetan templat tidak mempunyai sintaks untuk mengendalikan gelung — anda tidak boleh membina jadual daripada tatasusunan.
Untuk menangani batasan ini, ES6 menyediakan pembangun dan pereka perpustakaan dengan jenis rentetan templat yang lain — templat teg.
Sintaks templat tegadalah sangat mudah, anda hanya perlu memperkenalkan teg sebelum tanda belakang permulaan. Melihat contoh pertama: SaferHTML, kami akan menggunakan templat teg ini untuk menyelesaikan had pertama yang dinyatakan di atas: melarikan diri automatik bagi aksara khas.
Perlu diingat bahawa kaedah SaferHTML tidak disediakan oleh perpustakaan standard ES6, kami perlu melaksanakannya sendiri:
var message = SaferHTML`<p>${bonk.sender} has sent you a bonk.</p>`; var message = SaferHTML`<p>${bonk.sender} has sent you a bonk.</p>`;
Teg SaferHTML di sini ialah pengecam tunggal dan teg juga boleh menjadi atribut, seperti SaferHTML.escape, atau bahkan panggilan kaedah: SaferHTML.escape({unicodeControlCharacters: false}). Tepatnya, sebarang ungkapan ahli ES6 atau ungkapan panggilan boleh digunakan sebagai teg.
Dapat dilihat bahawa rentetan templat hanyalah gula sintaksis untuk penggabungan rentetan, manakala templat label sememangnya sesuatu yang berbeza sama sekali: panggilan fungsi.
Jadi, kod di atas adalah bersamaan dengan:
var message = SaferHTML(templateData, bonk.sender); var message = SaferHTML(templateData, bonk.sender);
Di mana templateData ialah tatasusunan rentetan yang tidak boleh diubah, dijana oleh enjin JS berdasarkan rentetan templat sumber Tatasusunan di sini mengandungi dua elemen, kerana rentetan templat mengandungi dua rentetan selepas dipisahkan oleh pemegang tempat Oleh itu, templateData akan menjadi seperti ini : Object.freeze(["e388a4556c0f65e1904146cc1a846bee", " telah menghantar bonk kepada anda.94b3e26ee717c64999d7867364b1b4a3"]
(Malah, terdapat atribut lain pada templateData: templateData.raw. Artikel ini tidak membincangkan atribut ini secara mendalam. Nilai atribut ini juga merupakan tatasusunan, termasuk semua bahagian rentetan dalam templat teg, tetapi rentetan Mengandungi jujukan melarikan diri yang kelihatan lebih seperti rentetan dalam kod sumber, seperti n Tag terbina dalam ES6 String.raw akan menggunakan rentetan ini )
.Ini membolehkan kaedah SaferHTML menghuraikan dua rentetan ini sesuka hati, dan terdapat N kaedah penggantian.
Sambil anda meneruskan membaca, anda mungkin tertanya-tanya bagaimana untuk melaksanakan kaedah SaferHTML.
Berikut ialah pelaksanaan (intisari):
function SaferHTML(templateData) { var s = templateData[0]; for (var i = 1; i < arguments.length; i++) { var arg = String(arguments[i]); // Escape special characters in the substitution. s += arg.replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">"); // Don't escape special characters in the template. s += templateData[i]; } return s; } function SaferHTML(templateData) { var s = templateData[0]; for (var i = 1; i < arguments.length; i++) { var arg = String(arguments[i]); // Escape special characters in the substitution. s += arg.replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">"); // Don't escape special characters in the template. s += templateData[i]; } return s; }
有了上面的方法,即使使用一个恶意的用户名,用户也是安全的。
一个简单的例子并不足以说明标签模板的灵活性,让我们重温一下上面列举的模板字符串的限制,看看我们还可以做些什么。
模板字符串不会自动转义特殊字符,但是我们可以通过标签模板来解决这个问题,事实上我们还可以将 SaferHTML 这个方法写的更好。从安全角度来看,这个 SaferHTML 非常脆弱。在 HTML 中,不同的地方需要用不同的方式去转义,SaferHTML 并没有做到。稍加思考,我们就可以实现一个更加灵活的 SaferHTML方法,能够将 templateData 中的任何一个 HTML 转义,知道哪个占位符是纯 HTML;哪个是元素的属性,从而需要对 ' 和 " 转义;哪个是 URL 的 query 字符串,从而需要用 URL 的 escaping 方法,而不是 HTML 的 escaping;等等。这似乎有些牵强,因为 HTML 转义效率比较低。辛运是的,标签模板的字符串是保持不变的,SaferHTML 可以缓存已经转义过的字符串,从而提高效率。
模板字符串并没有内置的国际化特性,但通过标签模板,我们可以添加该特性。Jack Hsu 的文章详细介绍了实现过程,看下面例子:
i18n`Hello ${name}, you have ${amount}:c(CAD) in your bank account.` // => Hallo Bob, Sie haben 1.234,56 $CA auf Ihrem Bankkonto. i18n`Hello ${name}, you have ${amount}:c(CAD) in your bank account.` // => Hallo Bob, Sie haben 1.234,56 $CA auf Ihrem Bankkonto.
上面例子中的 name 和 amount 很好理解,将被 JS 引擎替换为对应的字符串,但是还有一个没有见过的占位符::c(CAD),这将被 i18n 标签处理,从 i18n 的文档可知::c(CAD)表示 amount 是加拿大美元货币值。
模板字符串不能替代 Mustache 和 Nunjucks 这类模板引擎,部分原因在于模板字符串不支持循环和条件语句。我们可以编写一个标签来实现这类功能:
// Purely hypothetical template language based on // ES6 tagged templates. var libraryHtml = hashTemplate` <ul> #for book in ${myBooks} <li><i>#{book.title}</i> by #{book.author}</li> #end </ul> `; // Purely hypothetical template language based on // ES6 tagged templates. var libraryHtml = hashTemplate` <ul> #for book in ${myBooks} <li><i>#{book.title}</i> by #{book.author}</li> #end </ul> `;
灵活性还不止于此,需要注意的是,标签函数的参数不会自动转换为字符串,参数可以是任何类型,返回值也一样。标签模板甚至可以不需要字符串,你可以使用自定义标签来创建正则表达式、DOM 树、图片、代表整个异步进程的 Promise、JS 数据结构、GL 着色器…
标签模板允许库设计者创建强大的领域特定语言。这些语言可能看上去并不像 JS,但他们可以无缝嵌入到 JS 中,并且可以与语言的其余部分进行交互。顺便说一下,我还没有在其他语言中见过类似的特性,我不知道这个特性讲给我们带来些什么,但各种可能性还是非常令人兴奋的。