模板字符串的幾個特性:javascript
//嵌入變量 var name = "Kyle"; var greeting = `Hello ${name}!`; console.log( greeting ); // "Hello Kyle!" //多行 var text = `Now is the time for all good men to come to the aid of their country!`; console.log( text ); // Now is the time for all good men // to come to the aid of their // country!var text = //插入表達式 function upper(s) { return s.toUpperCase(); } var who = "reader"; var text = `A very ${upper( "warm" )} welcome to all of you ${upper( `${who}s` )}!`; console.log( text ); // A very WARM welcome // to all of you READERS!
模板字符串還能夠跟在一個函數後面,該函數將被調用來處理這個模板字符串。
這被成爲"標籤模板"功能。
alert`123` // 等同於 alert(123)
若是模板字符串中含有變量,標籤模板會進行特殊處理,它會根據嵌入的變量,把模板字符串拆開,
普通字符串組成數組作位第一個參數,插入的變量依次做爲第二個、第三個...變量。java
var a = 5; var b = 10; tag`Hello ${ a + b } world ${ a * b }`; // 等同於 tag(['Hello ', ' world ', ''], 15, 50); function tag(stringArr, value1, value2){ // ... } // 等同於 function tag(stringArr, ...values){ // ... }
tag函數的第一個參數是一個數組,該數組的成員是模板字符串中那些沒有變量替換的部分,也就是說,變量替換隻發生在數組的第一個成員與第二個成員之間、第二個成員與第三個成員之間,以此類推。es6
tag函數的其餘參數,都是模板字符串各個變量被替換後的值。因爲本例中,模板字符串含有兩個變量,所以tag會接受到value1和value2兩個參數。數組
我第一次看到標籤模板的時候,不由在想爲何要有標籤模板,它有什麼普通函數不能替代的地方呢?若是沒有不可替代的地方,那爲何還要創造
它呢?
答案是:標籤模板確實有它存在的意義,也有普通函數沒法替代它的地方。函數
const logArgs = (...args) => console.log(...args)
先用普通函數形式調用this
logArgs('a', 'b') // -> a b
再用一個簡單的模板字符串試試:spa
logArgs`` // -> ["", raw: Array(1)]
上面輸出了一個空數組,而後傳入一個有值的模板字符串:code
logArgs`I like pizza` // -> ["I like pizza"]
如今,進一步網模板字符串中傳入變量component
const favoriteFood = 'pizza' //看成普通函數調用,直接出入拼接的字符串 logArgs(`I like ${favoriteFood}.`) // -> I like pizza. //使用標籤模板,會輸出處理後的參數 const favoriteFood = 'pizza' logArgs`I like ${favoriteFood}.` // -> ["I like ", "."] "pizza"
變換過程是這樣的:blog
當咱們傳入多個變量時,每個插入的變量都做爲下一個參數了
const favoriteFood = 'pizza' const favoriteDrink = 'obi' logArgs`I like ${favoriteFood} and ${favoriteDrink}.` // -> ["I like ", " and ", "."] "pizza" "obi"
這樣看來,標籤模版有什麼大的做用呢?
//普通函數 logArgs(`Test ${() => console.log('test')}`) // -> Test () => console.log('test') console.log(() => console.log('test')) // () => console.log('test')
普通函數,遇到變量是一個函數是,會把函數變成字符串形式的,而沒有別的處理,看看標籤模板的特殊之處,
模板字符串中嵌入變量
logArgs`Test ${() => console.log('test')}` // -> ["Test", ""] () => console.log('test')
能夠看出,標籤模板把模板字符串中的變量解析了出來,函數仍是一個函數不會變成字符串。咱們有能力拿到函數,
那麼咱們也能夠執行這個函數
const execFuncArgs = (...args) => args.forEach(arg => { if (typeof arg === 'function') { arg() } })
上面的函數,咱們會忽略不是函數的參數,是函數就執行它
execFuncArgs('a', 'b') // -> undefined execFuncArgs(() => { console.log('this is a function') }) // -> "this is a function" execFuncArgs('a', () => { console.log('another one') }) // -> "another one"
讓咱們把它看成普通函數來調用帶有變量的模板字符串
execFuncArgs(`Hi, ${() => { console.log('Executed!') }}`) // -> undefined
爲何會是undfined
呢?由於,普通函數調用的方式,模板字符串會所有變成字符串的形式,變量也變成了字符串的形式
實際上調用參數是這樣的: "Hi, () => { console.log('I got executed!') }".
把上面的函數看成"標籤模板"來調用
execFuncArgs`Hi, ${() => { console.log('Executed!') }}` // -> "Executed!"
與以前相反,execFuncArgs
的第二個參數其實是一個函數,而後會執行這個函數。
由此能夠解決個人疑問了:
標籤模板能夠對傳入的模板字符串中的變量,進行提取,並進一步處理,普通函數根本取不到這些變量,就甭提進一步處理了。
「標籤模板」的一個重要應用,就是過濾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>`; message // <p><script>alert("abc")</script> has sent you a message.</p>
標籤模板的另外一個應用,就是多語言轉換(國際化處理)。
i18n`Welcome to ${siteName}, you are visitor number ${visitorNumber}!` // "歡迎訪問xxx,您是第xxxx位訪問者!"
還有common-tags
庫中的oneLine
標籤函數
import {oneLine} from 'common-tags' oneLine` foo bar baz ` // "foo bar baz"
總之,標籤模板功能很強大,可能一開始並不會以爲厲害之處,平時工做中也不會用到,可是在不少庫中會用到它,咱們
使用這些庫的時候也在不自覺中使用了標籤模板,能夠慢慢開始瞭解它,並使用它。
參考文章: