了解ES6中的模板字符串的标签函数

更新日期: 2021-11-26阅读: 872标签: es6

模板字符串是可能是我们耳熟能详的一个ES6新特性,它可以允许我们在字符串中插入变量,还能够换行等等,确实使用起来非常地方便。然而,ES6还新增了一种主要用于和模板字符串配合使用的标签函数

1.什么标签函数?

顾名思义,标签函数也是一种函数。这是一个很简单的标签函数声明:

function tagFoo() {
    console.log('这是一个标签函数');
}

仔细观察一下,看看tagFoo和我们常用的普通函数有什么区别呢?是不是看不出区别呢?得出这个结论很正常,因为标签函数其实就是一个函数,所以它的声明和函数声明是完全一样的。

那么,我们怎么知道tagFoo是一个标签函数呢,或者说标签函数相对于普通函数有什么特殊之处呢?答案是看tagFoo的调用方式

tagFoo();//这是一个标签函数
tagFoo`一个模板字符串`;//这是一个标签函数

标签函数除了可以作为普通函数,通过()调用之外,还可以使用模板字符串``来调用。换句话说,当一个函数使用模板字符串的方式调用时, 这个函数就可以被称为标签函数,所以我们不妨把标签函数理解为新增的一种函数调用方式。

那么我们可能会想到,这两种调用方式有什么不同呢?它们的返回值是什么呢?

不论哪种调用方式,都是调用了这个函数,最终的返回值也都是执行这个函数之后的结果。我们给tagFoo加上一个返回值来看看:

function tagFoo() {
    return '我是返回值';
}

let res1 = tagFoo(); 
let res2 = tagFoo`一个模板字符串`; 
console.log({ res1, res2 });//{ res1: '我是返回值', res2: '我是返回值' }

2.标签函数的参数

excuse me?难道这两种调用方式就只有看起来不一样吗?当然不是。想来我们都已经注意到了,普通函数的调用方式允许我们自行传入参数,而标签函数调用方式似乎没有给我们提供传入参数的机会。一起看看标签函数存在参数时,它的参数是什么吧:

function tagFoo(...args) {
    console.log(...args);
}

tagFoo`一个普通的模板字符串`; // [ '一个普通的模板字符串' ]
tagFoo`一个有插值的模板字符串:${'var'}`; //[ '一个有插值的模板字符串:', '' ] var
tagFoo`一个有插值的模板字符串:${'var1'}-${'var2'}`; //[ '一个有插值的模板字符串:', '-', '' ] var1 var2

从上面可以看出,标签函数调用时,接收到的一个参数总是一个数组,数组中的元素就是模板字符串中的字符串部分;从第二个参数开始的剩余参数接收的是模板字符串的插值变量,这些变量的数目是任意的。换种方式声明的话,可能更直观一些:

function tagFoo(templateStrings, ...insertVars) {
    console.log({ templateStrings, insertVars });
}
tagFoo`一个普通的模板字符串`; //{ templateStrings: [ '一个普通的模板字符串' ], insertVars: [] }
tagFoo`一个有插值的模板字符串:${'var'}`; //{ templateStrings: [ '一个有插值的模板字符串:', '' ], insertVars: [ 'var' ] }
tagFoo`一个有插值的模板字符串:${'var1'},${'var2'}`; //{ templateStrings: [ '一个有插值的模板字符串:', '-', '' ], insertVars: [ 'var1', 'var2' ] }

也可以用一张图来表示:


也许可以形容为,templateStrings中的每两个元素之间,都应该有一个insertVars中插入的变量。两个数组中元素的顺序是有对应关系的。

3.标签函数有什么用?

标签函数让我们根据模板字符串进行自己的逻辑行为,让一些操作变得很简单。

举一个简单的例子,将模板字符串中的价格n转成$n:

function $(templateStrings, ...insertVars) {
    return templateStrings.reduce((res, temp, i) => {
        return res + temp + (i >= insertVars.length ? '' : '$' + insertVars[i]);
    }, '');
}

console.log($`1号衣服原价${42},打折后的价格是${2}`); //1号衣服原价$42,打折后的价格是$2
console.log($`2号鞋子原价${58},打折后的价格是${88}`); //2号鞋子原价$58,打折后的价格是$88

不使用标签函数当然也能实现这个效果,也很简单:

function $(n) {
    return '$' + n;
}
console.log(`1号衣服原价${$(42)},打折后的价格是${$(2)}`); //1号衣服原价$42,打折后的价格是$2
console.log(`2号鞋子原价${$(58)},打折后的价格是${$(88)}`); //2号鞋子原价$58,打折后的价格是$88

使用哪种方式取决于我们自己的喜好。

但是,在处理一些特殊的情景时,标签函数可能会整一个大惊喜给到我们。

比如styled-components所做的:

const Button = styled.a`
  /* This renders the buttons above... Edit me! */
  display: inline-block;
  border-radius: 3px;
  padding: 0.5rem 0;
  margin: 0.5rem 1rem;
  width: 11rem;
  background: transparent;
  color: white;
  border: 2px solid white;

  /* The GitHub button is a primary button
   * edit this to target it specifically! */
  ${props => props.primary && css`
    background: white;
    color: black;
  `}
`

得到的Button就是一个react组件。通过styled-components,我们可以在JS中写css样式了!

我们也可以模仿styled-components,实现一个简单的styled.a

const styled = {
    a(stringProps, ...getProps) {
        const varProps = getProps.map((f) => f({}) || '');
        const style = stringProps
            .reduce((prop, stringProp, i) => {
                return (
                    prop +
                    stringProp +
                    (i >= varProps.length ? '' : varProps[i])
                );
            }, '')
            //删除注释和换行
            .replace(/(\n|(\/\*[\s\S]*?\*\/))/g, '')
            //删除空格
            .replace(
                /\s*?(?<propName>\w+):(?<propValue>[\s\S]*?);\s*/g,
                (...args) => {
                    const { propName, propValue } = args.pop();
                    return `${propName}:${propValue};`;
                }
            );

        //为了方便展示,返回一个字符串
        return `<ahljs-subst">${style}"></a>`;
    },
};
const Button = styled.a`
    /* This renders the buttons above... Edit me! */
    display: inline-block;
    border-radius: 3px;
    padding: 0.5rem 0;
    margin: 0.5rem 1rem;
    width: 11rem;
    background: transparent;
    color: white;
    border: 2px solid white;

    /* The GitHub button is a primary button
   * edit this to target it specifically! */
    ${(props) => !props.primary && 'background: white;'}
`;

console.log(Button);
//<a></a>

不得不说,标签函数在处理字符串的时候,真的很有吸引力。

当然,你会不会使用标签函数,还是取决于自己的喜好,萝卜白菜,各有所爱嘛。

来自:https://segmentfault.com/a/1190000041023016


链接: https://www.fly63.com/article/detial/10863

es6 箭头函数的使用总结,带你深入理解js中的箭头函数

箭头函数是ES6中非常重要的性特性。它最显著的作用就是:更简短的函数,并且不绑定this,arguments等属性,它的this永远指向其上下文的 this。它最适合用于非方法函数,并且它们不能用作构造函数。

详解JavaScript模块化开发require.js

js模块化的开发并不是随心所欲的,为了便于他人的使用和交流,需要遵循一定的规范。目前,通行的js模块规范主要有两种:CommonJS和AMD

js解构赋值,关于es6中的解构赋值的用途总结

ES6中添加了一个新属性解构,允许你使用类似数组或对象字面量的语法将数组和对象的属性赋给各种变量。用途:交换变量的值、从函数返回多个值、函数参数的定义、提取JSON数据、函数参数的默认值...

ES6中let变量的特点,使用let声明总汇

ES6中let变量的特点:1.let声明变量存在块级作用域,2.let不能先使用再声明3.暂时性死区,在代码块内使用let命令声明变量之前,该变量都是不可用的,4.不允许重复声明

ES6的7个实用技巧

ES6的7个实用技巧包括:1交换元素,2 调试,3 单条语句,4 数组拼接,5 制作副本,6 命名参数,7 Async/Await结合数组解构

ES6 Decorator_js中的装饰器函数

ES6装饰器(Decorator)是一个函数,用来修改类的行为 在设计阶段可以对类和属性进行注释和修改。从本质上上讲,装饰器的最大作用是修改预定义好的逻辑,或者给各种结构添加一些元数据。

基于ES6的tinyJquery

Query作为曾经Web前端的必备利器,随着MVVM框架的兴起,如今已稍显没落。用ES6写了一个基于class简化版的jQuery,包含基础DOM操作,支持链式操作...

ES6 中的一些技巧,使你的代码更清晰,更简短,更易读!

ES6 中的一些技巧:模版字符串、块级作用域、Let、Const、块级作用域函数问题、扩展运算符、函数默认参数、解构、对象字面量和简明参数、动态属性名称、箭头函数、for … of 循环、数字字面量。

Rest/Spread 属性_探索 ES2018 和 ES2019

Rest/Spread 属性:rest操作符在对象解构中的使用。目前,该操作符仅适用于数组解构和参数定义。spread操作符在对象字面量中的使用。目前,这个操作符只能在数组字面量和函数以及方法调用中使用。

使用ES6让你的React代码提升到一个新档次

ES6使您的代码更具表现力和可读性。而且它与React完美配合!现在您已了解更多基础知识:现在是时候将你的ES6技能提升到一个新的水平!嵌套props解构、 传下所有props、props解构、作为参数的函数、列表解构

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!