我對模版字符串中標籤模板的思考

模板字符串

模板字符串的幾個特性: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, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;");

    // 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>&lt;script&gt;alert("abc")&lt;/script&gt; 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"

總之,標籤模板功能很強大,可能一開始並不會以爲厲害之處,平時工做中也不會用到,可是在不少庫中會用到它,咱們
使用這些庫的時候也在不自覺中使用了標籤模板,能夠慢慢開始瞭解它,並使用它。

參考文章:

https://www.freecodecamp.org/...

https://mxstbr.blog/2016/11/s...

相關文章
相關標籤/搜索