• ES6 Features系列:Template Strings & Tagged Template Strings


    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函数

       答案是否定的

       原因是通过正斜杠(  )定义的多行字符串实际输出还是一行字符串而已,但通过反引号( `` )定义的是真实的多行字符串,且通过换行符(   )分隔每一行。

    // 通过定义多行的结果
    <div>    <h3>${ctx.title}</h3>    <span>${ctx.subtitle}</span>  </div>
    
    
    // 通过反引号定义多行的结果
    <div>
    
        <h3>${ctx.title}</h3>
    
        <span>${ctx.subtitle}</span>
    
      </div>

      那么当使用jQuery将反引号定义的HTML模板来生产DOM元素时就会直接报错了,这时我们需要删除这些控制字符。

    var removeCtlChar = raw => raw.replace(/[
    	vf]/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`	Hello${x}:${y+1}`
    console.log(ret) // 显示 "	Hello1:3"
    console.log(`	Hello${x}:${y+1}`) // 显示 "    Hello1:3"

       <Tagged Function>函数 有两个入参分别代表两类token。 {Array.<DOMString>} strings 为字符串类型的tokens,而 {...Any} vals 则为表达式占位符运算结果tokens。

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

       另外我们看到最后两行代码会发现 ` Hello${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/

  • 相关阅读:
    oracle连接方式、创建数据库用户、忘记数据库密码、用户锁定
    Hibernate延迟加载、三种状态、脏检查 缓存
    Hibernate入门案例及增删改查
    Hibernate 和快照
    学号20175313 《程序设计中临时变量的使用》第八周
    学号20175313 《Arrays和String单元测试》第八周
    学号 20175313 《实验二 面向对象程序设计》实验报告
    学号20175313 《结对编程四则运算》总结性编程 第七周
    学号 20175313《Java程序设计》 第七周学习总结
    20175313 张黎仙 《第六周 结对编程四则运算》 阶段性编程
  • 原文地址:https://www.cnblogs.com/fsjohnhuang/p/4601200.html
Copyright © 2020-2023  润新知