ES6 Features系列:Template Strings & Tagged Template Strings

1. Briefhtml

  ES6(ECMAScript 6th edition)於2015年7月份發佈,雖然各大瀏覽器仍未全面支持ES6,但咱們能夠在後端經過Node.js 0.12和io.js,而前端則經過Traceur或Babel這類Transpiler將ES6語法預轉譯爲ES5語法,來提早興奮一把。而僅需適配IE9+的朋友們如今更是能夠開始擼ES6了,而沒必要爲學哪門JavaScript超集語言而煩惱。(ES6又名爲ECMAScript 2015或JavaScript.next,ES4的部分較爲激進的特性被調用到該版本中實現。)前端

  ES6帶給咱們不少驚喜,如class、module、export和import等。但在學習和運用到項目中時,咱們須要注意如下兩點:es6

  1. ES6包含的是語法糖和語言、庫的bug fix,對工程性問題沒有太大的幫助;express

  2. 因爲Traceur和Babel沒法對ES6的全部特性進行完整高效的polyfill,所以咱們沒法徹底享用ES6的各項特性。後端

  最近接手一個項目的前端改造,正在嘗試全新的技術棧(Riot+ES6+Glup+Webpack),本系列文章將做爲理論+項目實踐的筆記供往後查閱。瀏覽器

 

2. What is Template Strings?ecmascript

  一言以蔽之,Template Strings就是讓咱們減小字符串手工拼接的工做量。函數

  2.1. Before ES6學習

// Sample 1: 單行字符串拼接
var operand1 = 1
  , operand2 = 2.1
var tpl1 = operand1 + ' + ' + operand2 + '~=' + parseInt(operand1+operand2)
var tpl2 = [operand1, ' + ' , operand2, '~=', parseInt(operand1 + operand2)].join('')
// Sample 2: 多行字符串拼接
var name = 'fsjohnhuang'
  , id = 'region'
var tpl1 = '<div id="' + id + '">'
  + '<a>' + name + '</a>'
  + '</div>'
var tpl2 = '<div id=" ' + id + ' ">\
  <a>' + name + '</a>\
  </div>'

  2.2. Embracing ES6lua

// Sample 1: 單行字符串拼接
var operand1 = 1
  , operand2 = 2.1
var tpl1 = `${operand1}+${operand2}~=${parseInt(operand1+operand2)}`
// Sample 2: 多行字符串拼接
var name = 'fsjohnhuang'
  , id = 'region'
var tpl1 = `<div id="${id}">
  <a>${name}</a>
  </div>`

  倘若瞭解過CoffeeScript,那麼會發現ES6的Template Strings怎麼這麼眼熟。Template Strings由兩部分組成:

    1. 模板起始符—— `` ,稱爲沉音符/反引號(grave accent),其內容被識別爲字符串模板。

    2. 表達式佔位符—— ${<expression>} ,<expression>爲JavaScript的有效表達式(如 name, 1==2等),所以 ${<expression>} 並非簡單的佔位符那麼簡單了。

  2.3. Cautions

    1.  ${<expression>} 中可訪問當前做用域所能訪問到變量和函數,如

var x = 1

(function(){
  var y = 2
  (function(b){
    var tpl = `${x},${y},${a},${b}` // 結果是 "1,2,undefined,5"
  }(5))
  var a = 3
  let c = 4 // 因爲採用let來聲明c變量,所以不會發生variable hoist
}())

    2.  ${<expression>} 是即時計算(real-time computing)的,經過函數加殼可實現延遲計算(lazy evaluation)

//real-time computing
var tpl = `${x},${y}`
var x = 1, y = 2
console.log(tpl) // "undefined, undefined"

// lazy evaluation
var tpl = ctx => `${ctx.x},${ctx.y}`
console.log(tpl({x:1, y:2})) // "1, 2"

   3. 多行陷阱(pitfall of multiline),在編寫HTML模板時我習慣以下寫法

var tpl = '<div>\
    <h3>${title}</h3>\
    <span>${subtitle}</span>\
  </div>'
// 而後是模板引擎解析tpl

   那如今是否就能夠毫無顧慮地改用Template Strings呢?

var tpl = ctx => `<div>
    <h3>${ctx.title}</h3>
    <span>${ctx.subtitle}</span>
  </div>`
// 直接調用tpl函數

   答案是否認的

   緣由是經過正斜槓( \ )定義的多行字符串實際輸出仍是一行字符串而已,但經過反引號( `` )定義的是真實的多行字符串,且經過換行符( \n )分隔每一行。

// 經過\定義多行的結果
<div>    <h3>${ctx.title}</h3>    <span>${ctx.subtitle}</span>  </div>


// 經過反引號定義多行的結果
<div>\n
    <h3>${ctx.title}</h3>\n
    <span>${ctx.subtitle}</span>\n
  </div>

  那麼當使用jQuery將反引號定義的HTML模板來生產DOM元素時就會直接報錯了,這時咱們須要刪除這些控制字符。

var removeCtlChar = raw => raw.replace(/[\r\n\t\v\f]/ig, '')

 

3. What is Tagged Template Strings?

  從上文咱們瞭解到Template Strings是以總體爲單位進行即時計算,也就是說留給咱們的自主操控能力是十分有限的。而Tagged Template Strings則大大加強了咱們的操控慾望。

  其實Tagged Template Strings實質上是對Template Strings進行Tokenize操做,從而細化咱們的可操做粒度。而詞法類型分爲 字符串表達式佔位符的運算結果

var x = 1, y = 2
var tpl = 'hello${x}:${y+1}'

// Tokenize後的結果
var tokens = ['hello', 1, ':', 3, ''] 

   具體玩法以下:

// 語法
<Tagged Function><Template Strings>

/** Sample **/
/* 定義<Tagged Function>
 * @param {Array.<DOMString>} strings - 字符串類型的tokens
 * @param {...Any} vals - 表達式佔位符的運算結果tokens
 * @returns {Any}
 */
var taggedFunc = (strings, ...vals){
  var ret = []
  for(let i = 0, len = strings.length ; i < len; ++i)
    ret.push(strings.raw[i], vals[i] || '')
  return ret
}

// 定義Template Strings
var x = 1, y =2
var ret = taggedFunc`\tHello${x}:${y+1}`
console.log(ret) // 顯示 "\tHello1:3"
console.log(`\tHello${x}:${y+1}`) // 顯示 "    Hello1:3"

   <Tagged Function>函數 有兩個入參分別表明兩類token。 {Array.<DOMString>} strings 爲字符串類型的tokens,而 {...Any} vals 則爲表達式佔位符運算結果tokens。

   而須要注意的是: strings.length === vals.length + 1 

   另外咱們看到最後兩行代碼會發現 `\tHello${x}:${y+1}` 中的製表符將在輸出結果中起效,而通過Tagged Function處理的則按普通字符輸出而已。其實這是經過 {Array.<DOMString>}strings.raw屬性 操做strings中token的結果,也就是說strings.raw屬性將對控制符進行轉義從而實現按照普通字符輸出。

   3.1. 內置的Tagged Function——String.raw

     其做用與上述的taggedFunc同樣,就是將按普通字符輸出Template Strings中的控制符。

   3.2. Cautions

     1. Tagge Template Strings的語法是Template Strings緊跟在Tagged Function後面,二者間不能有空格或製表符等。

     2. vals是運算後的實際值,若要延遲計算依然須要加殼。

     3. @ruanyifeng老師說可經過Tagged Function來自定義帶流程控制的模板語言

// 下面的hashTemplate函數
// 是一個自定義的模板處理函數
var libraryHtml = hashTemplate`
  <ul>
    #for book in ${myBooks}
      <li><i>#{book.title}</i> by #{book.author}</li>
    #end
  </ul>
`;

        本人以爲這種用法不可取,Tagged Function原本就按照自身規則對模板進行Tokenize,而後咱們在此基礎上對結果進行二次Tokenize,那還不如直接按本身定義的規則來作詞法分析更省心。

 

4. Conclusion

   Template Strings和Tagged Template Strings 都可經過Traceur和Babel作transpile,因此咱們如今就能夠擼起了,開幹吧各位!

   尊重原創,轉載請註明來自:http://www.cnblogs.com/fsjohnhuang/p/4601200.html  肥子John^_^

 

5. Thanks

    http://es6.ruanyifeng.com/#docs/string

    http://www.sitepoint.com/understanding-ecmascript-6-template-strings/

相關文章
相關標籤/搜索