原文地址:http://www.cnblogs.com/goloving/p/7868865.htmljavascript
JS 的字符串相對其餘語言來講功能老是有限的,事實上,ES5中一直缺少許多特性,如多行字符串、字符串格式化、HTML轉義等。ES6經過模板字面量的方式進行了填補,模板字面量試着跳出JS已有的字符串體系,經過一些全新的方法來解決相似的問題。html
模板字面量是加強版的字符串,它用反引號(`)標識java
自javascript誕生起,開發者們就一直在尋找一種能建立多行字符串的方法。若是使用雙引號或單引號,字符串必定要在同一行才行數組
一、反斜槓
因爲javascript長期以來一直存在一個語法bug,在換行以前的反斜線( \ )能夠承接下一行的代碼,因而能夠利用這個bug來建立多行字符串,可是字符串打印輸出時不會有換行,由於反斜線被視爲延續符號而不是新行的符號。爲了在輸出中顯示換行,須要手動加入換行符函數
var message = "Multiline string"; console.log(message); // 報錯:Uncaught SyntaxError: Invalid or unexpected token
var message = "Multiline \ string"; console.log(message); // "Multiline string"
var message = "Multiline \n\ string"; // "Multiline // string" console.log(message);
在全部主流的 JS 引擎中,此代碼都會輸出兩行,可是該行爲被認定爲一個 bug ,而且許多開發者都建議應避免這麼作。在ES6以前,一般都依靠數組或字符串的拼接來建立多行字符串。code
var message = ["Multiline ","string"].join("\n"); let message = "Multiline \n" +"string";
JS一直以來都不支持多行字符串,開發者的種種解決方法都不夠完美。htm
二、反引號對象
ES6 的模板字面量使多行字符串更易建立,由於它不須要特殊的語法,只需在想要的位置直接換行便可,此處的換行會同步出如今結果中。blog
let bb = `Multiline string`; // "Multiline // string" console.log(bb); console.log(bb.length); // 16
在反引號以內的全部空白符都是字符串的一部分,所以須要特別留意縮進。模板引擎
模板字面量裏的全部空白符都被視爲字符串自身的一部分。
固然,也能夠在模板字面量中使用 \n 來指示換行的插入位置
let aaa=`aab\ndd`; console.log(aaa,aaa.length) //aab //dd //6
模板字面量看上去僅僅是普通JS字符串的升級版,但兩者之間真正的區別在於模板字面量的變量佔位符。變量佔位符容許將任何有效的JS表達式嵌入到模板字面量中,並將其結果輸出爲字符串的一部分。
變量佔位符由起始的 ${ 與結束的 } 來界定,之間容許放入任意的 JS 表達式。最簡單的變量佔位符容許將本地變量直接嵌入到結果字符串中。
let name = "Nicholas", message = `Hello, ${name}.`; console.log(message); // "Hello, Nicholas."
佔位符 ${name} 會訪問本地變量 name ,並將其值插入到 message 字符串中。 message變量會當即保留該佔位符的結果
既然佔位符是JS表達式,那麼可替換的就不只僅是簡單的變量名。能夠輕易嵌入運算符、函數調用等
let count = 10, price = 0.25, message = `${count} items cost $${(count * price).toFixed(2)}.`; console.log(message); // "10 items cost $2.50."
function fn() { return "Hello World"; } `foo ${fn()} bar` // foo Hello World bar
模板字面量自己也是 JS 表達式,所以能夠將模板字面量嵌入到另外一個模板字面量內部
let name = "Nicholas", message = `Hello, ${ `my name is ${ name }` }.`; console.log(message); // "Hello, my name is Nicholas."
模板字面量真正的威力來自於標籤模板,每一個模板標籤均可以執行模板字面量上的轉換並返回最終的字符串值。標籤指的是在模板字面量第一個反引號'`'前方標註的字符串
let message = tag`Hello world`; //在這個示例中, tag 就是應用到 `Hello world` 模板字面量上的模板標籤
一、定義標籤
標籤能夠是一個函數,調用時傳入加工過的模板字面量各部分數據,但必須結合每一個部分來建立結果。第一個參數是一個數組,包含Javascript解釋事後的字面量字符串,它以後的全部參數都是每個佔位符的解釋值
標籤函數一般使用不定參數特性來定義佔位符,從而簡化數據處理的過程
function tag(literals, ...substitutions) { // 返回一個字符串 }
爲了進一步理解傳遞給tag函數的參數,查看如下代碼
let count = 10, price = 0.25, message = passthru`${count} items cost $${(count * price).toFixed(2)}.`;
若是有一個名爲passthru()的函數,那麼做爲一個模板字面量標籤,它會接受3個參數:
首先是一個literals數組,包含如下元素:
一、第一個佔位符前的空字符串("")
二、第1、二個佔位符之間的字符串(" items cost $")
三、第二個佔位符後的字符串(".")
下一個參數是變量count的解釋值,傳參爲10,它也成爲了substitutions數組裏的第一個元素
最後一個參數是(count*price).toFixed(2)的解釋值,傳參爲2.50,它是substitutions數組裏的第二個元素
注意:literals裏的第一個元素是一個空字符串,這確保了literals[0]老是字符串的始端,就像literals[literals.length-1]老是字符串的結尾同樣。substitutions的數量總比literals少一個,這也意味着表達式substitutions.Iength === literals.Iength-1的結果總爲true
var a = 5; var b = 10; tag`Hello ${ a + b } world ${ a * b }`; // 等同於 tag(['Hello ', ' world ', ''], 15, 50);
經過這種模式,咱們能夠將literals和substitutions兩個數組交織在一塊兒重組結果字符串。先取出literals中的首個元素,再取出substitution中的首個元素,而後交替繼續取出每個元素,直到字符串拼接完成。因而能夠經過從兩個數組中交替取值的方式模擬模板字面量的默認行爲。
function passthru(literals, ...substitutions) { let result = ""; // 僅使用 substitution 的元素數量來進行循環 for (let i = 0; i < substitutions.length; i++) { result += literals[i]; result += substitutions[i]; } // 添加最後一個字面量 result += literals[literals.length - 1]; return result; } let count = 10, price = 0.25, message = passthru`${count} items cost $${(count * price).toFixed(2)}.`; console.log(message); // "10 items cost $2.50."
這個示例定義了一個passthru標籤,模擬模板字面量的默認行爲,展現了一次轉換過程。此處的小竅門是使用substitutions.length來爲循環計數。
二、應用
「標籤模板」的一個重要應用,就是過濾HTML字符串,防止用戶輸入惡意內容
var message = SaferHTML`<p>${sender} has sent you a message.</p>`; 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; }
上面代碼中,sender
變量每每是用戶提供的,通過SaferHTML
函數處理,裏面的特殊字符都會被轉義
var sender = '<script>alert("abc")</script>'; // 惡意代碼 var message = SaferHTML`<p>${sender} has sent you a message.</p>`; console.log(message);// <p><script>alert("abc")</script> has sent you a message.</p>
標籤模板的另外一個應用,就是多語言轉換(國際化處理)
i18n`Welcome to ${siteName}, you are visitor number ${visitorNumber}!` // "歡迎訪問xxx,您是第xxxx位訪問者!"
模板字符串自己並不能取代模板引擎,由於沒有條件判斷和循環處理功能,可是經過標籤函數,能夠本身添加這些功能
// 下面的hashTemplate函數 // 是一個自定義的模板處理函數 var libraryHtml = hashTemplate` <ul> for book in ${myBooks} <li><i>${book.title}</i> by ${book.author}</li> end </ul> `;
String.raw`方法,每每用來充當模板字面量的處理函數,返回一個斜槓都被轉義(即斜槓前面再加一個斜槓)的字符串,對應於替換變量後的模板字面量
let message1 = `Multiline\nstring`, message2 = String.raw`Multiline\nstring`; console.log(message1); // "Multiline // string" console.log(message2); // "Multiline\\nstring"
String.raw`Hi\n${2+3}!`; // "Hi\\n5!" String.raw`Hi\u000A!`; // 'Hi\\u000A!' //若是原字符串的斜槓已經轉義,那麼String.raw不會作任何處理 String.raw`Hi\\n` // "Hi\\n"
String.raw方法能夠做爲處理模板字面量的基本方法,它會將全部變量替換,並且對斜槓進行轉義,方便下一步做爲字符串來使用。
String.raw方法也能夠做爲正常的函數使用。這時,它的第一個參數,應該是一個具備raw屬性的對象,且raw屬性的值應該是一個數組
String.raw({ raw: 'test' }, 0, 1, 2);// 't0e1s2t' // 等同於 String.raw({ raw: ['t','e','s','t'] }, 0, 1, 2);