标签模板

1,500 阅读2分钟

摘自《ES6标准入门》

标签模板其实不是模板,而是函数调用的一种特殊方式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。

但是,如果模板字符串中有变量,就不再是简单的调用了,而是要将模板字符串先处理成多个参数,再调用函数。

    var a = 5;
    var b = 10;
    
    tag`Hello ${a + b} world ${a * b}`
    // 等同于
    tag(['Hello ', ' world ', ''], 15, 50)

tag 函数的第一个参数是一个数组,该数组的成员是模板字符串中那些没有变量替换的部分,也就是说,变量替换只发生在数组的第一个成员与第二个成员之间、第二个成员与第三个成员之间,以此类推。 `tag 函数的其他参数都是模板字符串各个变量被替换后的值。由于本例中,模板字符串含有两个变量,因此 tag 会接收到 value1 和 value2 两个参数。 tag 函数所有参数的实际值如下。

  • 第一个参数:['Hello ', ' world ', '']
  • 第二个参数:15
  • 第三个参数:50

也就是说,tag 函数实际上以下面的形式调用。 tag(['Hello ', ' world ', ''], 15, 50)

我们可以按照需要编写 tag 函数的代码。下面是 tag 函数的一种写法以及运行结果。

    var a = 5;
    var b = 10;
    
    function tag(s, v1, v2) {
        console.log(s[0])
        console.log(s[1])
        console.log(s[2])
        console.log(v1)
        console.log(v2)
        
        return 'OK'
    }
    
    tag`Hello ${a + b} world ${a * b}`
    // 'Hello'
    // ' world '
    // ''
    // 15
    // 50
    // 'OK'

下面一个更复杂的例子:

    var total = 30;
    var msg = passthru`The total is ${total} (${total*1.5} with tax)`;
    
    function passthru(literals) {
    	var result = ''
    	var i = 0;
    	
    	while (i < literals.length) {
    		result += literals[i++];
    		if (i < arguments.length) {
    			result += arguments[i]	
    		}
    	}
    	return result
    }
    
    msg // "The total is 30 (45 with tax)"

上面这个例子展示了如何将各个参数按照原来的位置拼接回去。 passthru 函数采用 rest 参数的写法如下。

    function passthru(literals, ...values) {
        var output = '';
        for (var index = 0;index < valus.length; index++) {
            output += literals[index]
            return output
        }
    }

“标签模板” 的一个重要应用就是过滤就是 HTML 字符串,防止用户输入恶意内容。

    var message = SaferHTML`<P>${sender} has sent you message.</p>`
    
    function SaferHTML(templateData) {
        var s = templateData[0];
        for(var i = 1; i < arguments.length; i++) {
            var arg = String(arguments[i]);
            
            // 替换转义字符
            s += arg.replace(/&/g, '&amp;')
                    .replace(/</g, '&lt;')
                    .replace(/>/g, '&gt;')
                    
            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>

标签模板的另一个应用是多国语言转换(国际化处理)。