如何将 JavaScript 变量转换为模板字面量?

9

我希望能够将我生成并储存在一个字符串中的文本,像模板文字一样使用。

var generatedText = "Pretend this text was generated and then stored in a variable. "; 
generatedText = "But I still need to use it as a template it to get ${variable}.";

var variable = "Successs!!!!";

console.log(generatedText);
//prints 'But I still need to interpolate it to get ${variable}.'
//how can I make it print using variable in it like a template as if it were doing this
console.log(`But I still need to use it as a template it to get ${variable}.`);
//prints 'But I still need to use it as a template it to get Successs!!!!.'

如何将生成的文本变为模板字符串?

如果可能,需要将generatedText置于变量中,因此我需要找到一种方法将其转换为模板字符串。

编辑:

我没想到我需要声明这一点,但是我也不想使用eval来评估随机代码......


3
为什么不直接使用模板字面量,而是要先将其保存为字符串,再尝试将其作为模板字面量使用?你想实现什么效果? - Code Maniac
你的问题不是很清楚。 - mwilson
1
@MeirKeller 评论不应该作为答案。如果你认为你有一个好的答案,把它发表为答案。 - mwilson
1
https://dev59.com/HV4b5IYBdhLWcg3waA5P - epascarello
请参见“ES6模板文字可以在运行时替换吗” https://dev59.com/HV4b5IYBdhLWcg3waA5P - Chris
1
重新打开,因为重复的几个顶级答案都不如CertainPerformance的好。底部有一些接近的答案,但似乎这里不需要嵌套属性。 - Ry-
4个回答

19

对于一般情况,您可以使用替换器函数将${someProp}的每个出现替换为对象上的someProp属性:

对于一般情况,您可以使用替换器函数将${someProp}的每个出现替换为对象上的someProp属性:

const interpolate = (str, obj) => str.replace(
  /\${([^}]+)}/g,
  (_, prop) => obj[prop]
);

const generatedText = "But I still need to use it as a template it to get ${variable}.";
const variable = "Successs!!!!";

console.log(interpolate(generatedText, { variable }));

正则表达式\${([^}]+)}的含义是:

  • \$ - 字面量 $
  • { - 字面量 {
  • ([^}]+) 第一个(也是唯一的)捕获组:
    • [^}]+ - 一个或多个非 } 字符
  • } - 字面量 }

由于在括号中找到的 prop 是属性名,所以用 obj[prop] 替换为期望的替换值。


你如何扩展你的解决方案来处理 ${obj.foo.bar} - pery mimon
请参见 https://dev59.com/EGw15IYBdhLWcg3wntOh - 使用 reduce 迭代 . 之间的子字符串以获取嵌套值。 - CertainPerformance
@CertainPerformance - 你真是个英雄! - Michael

7
下面的interpolate函数是对这个答案进行了扩展,支持简单的嵌套对象字段引用(例如:a.b.c)。

function interpolate(s, obj) {
  return s.replace(/[$]{([^}]+)}/g, function(_, path) {
    const properties = path.split('.');
    return properties.reduce((prev, curr) => prev && prev[curr], obj);
  })
}

console.log(interpolate('hello ${a.b.c}', {a: {b: {c: 'world'}}}));
// Displays 'hello world'


2
下面的插值函数是上述解决方案的扩展版本,支持简单嵌套对象字段引用,并添加了数组的支持(例如:a[0][2].b.c)。

const interpolate = (str, obj) => {
  return str.replace(/\${([^}]+)}/g, (_, target) => {
    let keys = target.split(".");
    return keys.reduce((prev, curr) => {
      if (curr.search(/\[/g) > -1) {
        //if element/key in target array is array, get the value and return
        let m_curr = curr.replace(/\]/g, "");
        let arr = m_curr.split("[");
        return arr.reduce((pr, cu) => {
          return pr && pr[cu];
        }, prev);
      } else {
        //else it is a object, get the value and return
        return prev && prev[curr];
      }
    }, obj);
  });
};

let template = "hello ${a[0][0].b.c}";
let data = {
  a: [
    [{
      b: {
        c: "world",
        f: "greetings"
      }
    }, 2], 3
  ],
  d: 12,
  e: 14
}
console.log(interpolate(template, { ...data
}));


1
你应该模拟模板字面量,因为让来自 ~某处~ 的文本运行任意JavaScript,就像一个真正的模板字面量的${}部分通常不是一个好主意:
generatedText.replace(/\$\{variable}/g, variable);

某些性能答案更接近我的需求,因为我可以在单次传递中替换多个不同变量的实例,但这个答案也是正确的,做我所要求的事情,并且不使用 eval。 - Trevor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接