文章出處

1. Brief

  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等。但在學習和運用到項目中時,我們需要注意以下兩點:

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

  2. 由于Traceur和Babel無法對ES6的所有特性進行完整高效的polyfill,因此我們無法完全享用ES6的各項特性。

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

 

2. What is Template Strings?

  一言以蔽之,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 ES6

// 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/


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()