关于javascript:了解ES6中的模板字符串的标签函数

3次阅读

共计 3630 个字符,预计需要花费 10 分钟才能阅读完成。

模板字符串是可能是咱们耳熟能详的一个 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 `<a style="${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 style="display: inline-block;border-radius: 3px;padding: 0.5rem 0;margin: 0.5rem 1rem;width: 11rem;background: transparent;color: white;border: 2px solid white;background: white;"></a>

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

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

正文完
 0