【高频考点精讲】模板字符串的进阶用法,远不止字符串拼接这么简单

模板字符串的进阶玩法,你可能只用了它1%的功能

大家好,我是全栈老李。今天聊个看似简单但暗藏玄机的东西——模板字符串。很多人觉得它就是个高级版字符串拼接,那可就太小看ES6了。

你以为的${}只是冰山一角

先看个最基础的用法,老司机们肯定都见过:

const name = '全栈老李';
console.log(`大家好,我是${
              name}`); // 大家好,我是全栈老李

但如果你以为模板字符串就这点能耐,那就好比把iPhone当老人机用。下面这些骚操作才是重头戏。

进阶玩法一:带标签的模板字符串

先看这段代码,猜猜输出什么:

function leeTag(strings, ...values) {
            
  console.log(strings);     // ["吃了", "个包子", ""]
  console.log(values);      // [3, "韭菜"]
  return '饱了';
}

const count = 3;
const type = '韭菜';
const result = leeTag`吃了${
              count}个包子${
              type}`;

console.log(result); // 输出什么?(全栈老李提示:注意返回值)

这个leeTag就是个标签函数,它能拦截模板字符串的解析过程。strings是静态文本部分(被变量插值分割后的数组),values是动态插值部分。

真实应用场景

国际化文案处理(动态插入多语言变量)
安全过滤(自动转义HTML标签防XSS)
样式组件(比如styled-components底层原理)

举个防XSS的例子:

function safeHtml(strings, ...values) {
            
  let result = '';
  strings.forEach((str, i) => {
            
    result += str;
    if (i < values.length) {
            
      result += String(values[i])
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;");
    }
  });
  return result;
}

const userInput = '<script>alert("嘿嘿")</script>';
const safeOutput = safeHtml`<div>${
              userInput}</div>`;
// 输出:<div>&lt;script&gt;alert("嘿嘿")&lt;/script&gt;</div>

(全栈老李小贴士:标签函数的第一个参数总有n+1个元素,values总有n个元素)

进阶玩法二:嵌套模板与动态模板

模板字符串可以无限套娃:

const isVIP = true;
const discount = 0.8;
const priceTemplate = 
  `当前价格:¥${
              100 * (isVIP ? discount : 1)}(${
              isVIP ? '会员价' : '原价'})`;

// 更复杂的嵌套
const generateUI = (type) => {
            
  const base = `
    <div class="card">
      ${
              type === 'premium' 
        ? `<img src="gold-icon.png"/>` 
        : `<span>普通用户</span>`}
    </div>
  `;
  return base;
};

冷知识:模板字符串的缩进会被保留,如果嫌弃换行符和空格,可以这样处理:

const sql = `
  SELECT * FROM users
  WHERE id = ${
              id}
`.trim().replace(/s+/g, ' ');

进阶玩法三:与函数式编程的化学反应

配合高阶函数玩出花样:

const data = [
  {
             name: '张三', score: 85 },
  {
             name: '李四', score: 92 }
];

const createRow = ({
             name, score}) => `
  <tr>
    <td>${
              name}</td>
    <td>${
              score.toFixed(2)}</td>
    <td>${
              score >= 90 ? '优秀' : '良好'}</td>
  </tr>
`;

const tableHtml = `
  <table>
    ${
              data.map(createRow).join('')}
  </table>
`;

(全栈老李友情提示:array.map().join('')是生成动态HTML的经典模式)

课后作业:实现一个模板引擎

来道面试真题练练手:

/**
 * 实现一个简易模板引擎
 * @param {string} template 模板字符串,如"Hello, {
            {name}}!"
 * @param {object} data 数据对象,如{name: 'World'}
 * @return {string} 渲染后的字符串
 * 示例:
 * render("Hello, {
            {name}}!", {name: '全栈老李'}) 
 * 输出:"Hello, 全栈老李!"
 */
function render(template, data) {
            
  // 你的代码写在这里
  return result;
}

要求

能处理{
{prop}}
格式的插值
处理不存在的属性时返回空字符串
禁止使用eval/new Function

在评论区留下你的答案,我会随机抽几位同学的代码进行点评。下期公布参考答案时,会分析几种典型实现方案的性能差异(包括正则优化技巧)。

我是全栈老李,我们下次见!

🔥 必看面试题

【初级】前端开发工程师面试100题(一)
【初级】前端开发工程师面试100题(二)
【初级】前端开发工程师的面试100题(速记版)

我是全栈老李,一个资深Coder!

写码不易,如果你觉得本文有收获,点赞 + 收藏走一波!感谢鼓励🌹🌹🌹

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容