【问题标题】:Convert a string to a template string将字符串转换为模板字符串
【发布时间】:2015-05-24 18:57:32
【问题描述】:

是否可以像普通字符串一样创建模板字符串,

let a = "b:${b}";

然后将其转换为模板字符串,

let b = 10;
console.log(a.template()); // b:10

没有evalnew Function等动态代码生成方式?

【问题讨论】:

  • 您找到实现此目的的方法了吗?有一天我可能需要这样做,我很想知道你得到了什么。
  • @BryanRayner 假设您的 js 程序正在尝试从 rest API 获取数据,其 url 在 config.js 文件中作为字符串“/resources//update/”而你从您的程序中动态放置“resource_id”。除非您想将该 url 拆分为多个部分并保存在不同的区域,否则您需要某种字符串模板处理。
  • 不推荐使用 eval 来更好地使用 eval 而不是使用它,强烈建议不要使用它,因此请不要使用它 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ……!让 b = 10;让 a="b:${b}";让响应 = a.replace(/\${\w+}/ ,b);控制台.log(响应);
  • @Ryu_hayabusa 我相信这里的目标是能够在没有模板预处理的情况下引用这些变量值,以便我们可以实时操作它们而不仅仅是在服务器上-一边。

标签: javascript ecmascript-6 eval template-strings


【解决方案1】:

在我的项目中,我使用 ES6 创建了类似的东西:

String.prototype.interpolate = function(params) {
  const names = Object.keys(params);
  const vals = Object.values(params);
  return new Function(...names, `return \`${this}\`;`)(...vals);
}

const template = 'Example text: ${text}';
const result = template.interpolate({
  text: 'Foo Boo'
});
console.log(result);

【讨论】:

  • 嗨,您的解决方案效果很好,但是当我在 React Native(构建模式)中使用它时,它会抛出一个错误:Invalid character '`',虽然它在我在调试模式下运行。看起来,babel问题,有什么帮助吗?
  • @MohitPandey 当我在 PhantomJS 下运行此代码的测试并且它在 chrome 下通过时,我遇到了同样的错误。如果是这样的话,我认为 PhantomJS 的新 beta 版本即将推出,对 ES6 的支持更好,你可以尝试安装它。
  • 抱歉,现在可以使用了:document.querySelector("template").innerHTML.interpolate(viewerData);
  • 虽然这是对eval() 的改进,因为它不会泄露您的范围,但毫无价值,Function() constructor 确实eval() 共享一些安全问题,因为它仍在将字符串评估为 JavaScript,因此应谨慎对待。 MDN 在never use eval() 上的文档对此进行了更详细的介绍。
  • 这应该是最好的答案,但是在浏览器中避免eval()new Function()是有安全原因的。
【解决方案2】:

由于您的模板字符串必须动态(在运行时)引用b 变量,所以答案是:不,没有动态代码生成是不可能的。

但是,eval 非常简单:

let tpl = eval('`'+a+'`');

【讨论】:

  • eval 不安全,其他动态代码生成方式也是如此
  • @KOLANICH 对于这种特殊情况 - 在a 字符串中转义后引号,它的不安全性将大大降低:let tpl = eval('`'+a.replace(/`/g,'\\`')+'`');。我认为更重要的是eval 阻止编译器优化您的代码。但我认为这与这个问题无关。
  • 其实你也可以在模板字符串里面运行函数。
  • @KOLANICH 抱歉,您不喜欢 eval。但是,请记住,模板文字本身就是eval 的一种形式。两个例子: var test=Result: ${alert('hello')};变种测试=Result: ${b=4};两者最终都会在脚本的上下文中执行任意代码。如果你想允许任意字符串,你也可以允许eval
  • 小心。因为像 babel 这样的东西不会转译,所以这段代码在 IE 中不起作用
【解决方案3】:

不,没有动态代码生成就没有办法做到这一点。

但是,我创建了一个函数,它将常规字符串转换为一个函数,该函数可以在内部使用模板字符串提供值映射。

Generate Template String Gist

/**
 * Produces a function which uses template strings to do simple interpolation from objects.
 * 
 * Usage:
 *    var makeMeKing = generateTemplateString('${name} is now the king of ${country}!');
 * 
 *    console.log(makeMeKing({ name: 'Bryan', country: 'Scotland'}));
 *    // Logs 'Bryan is now the king of Scotland!'
 */
var generateTemplateString = (function(){
    var cache = {};

    function generateTemplate(template){
        var fn = cache[template];

        if (!fn){
            // Replace ${expressions} (etc) with ${map.expressions}.

            var sanitized = template
                .replace(/\$\{([\s]*[^;\s\{]+[\s]*)\}/g, function(_, match){
                    return `\$\{map.${match.trim()}\}`;
                    })
                // Afterwards, replace anything that's not ${map.expressions}' (etc) with a blank string.
                .replace(/(\$\{(?!map\.)[^}]+\})/g, '');

            fn = Function('map', `return \`${sanitized}\``);
        }

        return fn;
    }

    return generateTemplate;
})();

用法:

var kingMaker = generateTemplateString('${name} is king!');

console.log(kingMaker({name: 'Bryan'}));
// Logs 'Bryan is king!' to the console.

希望这对某人有所帮助。如果您发现代码有问题,请及时更新 Gist。

【讨论】:

  • 谢谢!我使用它而不是 javascript sprintf 解决方案。
  • 不适用于每个模板 var test = generateTemplateString('/api/${param1}/${param2}/') console.log(test({param1: 'bar', param2: 'foo'})) return /api/bar//
  • 谢谢,已修复。正则表达式包含 ${param1}/${param2} 的单个匹配项,而应该是两个匹配项。
  • 请注意,这在 IE11 中不起作用,因为缺少对反引号的支持。
  • 当然,如果浏览器不支持模板字符串,这种方法就行不通。如果你想在不支持的浏览器中使用模板字符串,我建议使用 TypeScript 之类的语言,或者 Babel 之类的转译器;这是让 ES6 进入旧浏览器的唯一方法。
【解决方案4】:

你在这里要求什么:

//non working code quoted from the question
let b=10;
console.log(a.template());//b:10

eval 完全等效(在功率和安全性方面):获取包含代码的字符串并执行该代码的能力;以及执行代码在调用者环境中查看局部变量的能力。

在 JS 中,函数无法在其调用者中查看局部变量,除非该函数是 eval()。连Function()都做不到。


当你听说 JavaScript 中出现了一种叫做“模板字符串”的东西时,很自然地会认为它是一个内置的模板库,比如 Mustache。它不是。主要是 string interpolation 和 JS 的多行字符串。不过,我认为这将在一段时间内成为一个普遍的误解。 :(

【讨论】:

  • TBH 这就是我的想法。会非常非常方便。
  • 这(仍然)有效吗?我收到template is not a function
  • 此答案顶部的代码块是该问题的引用。它不起作用。
【解决方案5】:

这里发布了许多好的解决方案,但还没有一个使用ES6 String.raw method。这是我的贡献。它有一个重要的限制,它只接受来自传入对象的属性,这意味着模板中的任何代码都不会执行。

function parseStringTemplate(str, obj) {
    let parts = str.split(/\$\{(?!\d)[\wæøåÆØÅ]*\}/);
    let args = str.match(/[^{\}]+(?=})/g) || [];
    let parameters = args.map(argument => obj[argument] || (obj[argument] === undefined ? "" : obj[argument]));
    return String.raw({ raw: parts }, ...parameters);
}
let template = "Hello, ${name}! Are you ${age} years old?";
let values = { name: "John Doe", age: 18 };

parseStringTemplate(template, values);
// output: Hello, John Doe! Are you 18 years old?
  1. 将字符串拆分为非参数文本部分。见regex
    parts: ["Hello, ", "! Are you ", " years old?"]
  2. 将字符串拆分为属性名称。如果匹配失败,则为空数组。
    args: ["name", "age"]
  3. 按属性名称映射来自obj 的参数。解决方案受到浅层映射的限制。未定义的值用空字符串替换,但也接受其他虚假值。
    parameters: ["John Doe", 18]
  4. 使用String.raw(...) 并返回结果。

【讨论】:

  • 出于好奇,String.raw 在这里实际提供了什么价值?看来您正在完成解析字符串并跟踪替换内容的所有工作。这与简单地反复调用.replace() 有很大不同吗?
  • 公平点,@SteveBennett。我在将普通字符串转换为模板字符串时遇到了一些问题,并通过自己构建原始对象找到了解决方案。我想它将 String.raw 简化为连接方法,但我认为它工作得很好。不过,我希望看到.replace() 的一个很好的解决方案:) 我认为可读性很重要,所以在我自己使用正则表达式时,我尝试命名它们以帮助理解这一切......
【解决方案6】:

TLDR: https://jsfiddle.net/bj89zntu/1/

似乎每个人都担心访问变量。为什么不直接通过它们?我确信在调用者中获取变量上下文并将其传递下来不会太难。采用 ninjagecko's answer 获取 obj 的 props。

function renderString(str,obj){
    return str.replace(/\$\{(.+?)\}/g,(match,p1)=>{return index(obj,p1)})
}

这里是完整的代码:

function index(obj,is,value) {
    if (typeof is == 'string')
        is=is.split('.');
    if (is.length==1 && value!==undefined)
        return obj[is[0]] = value;
    else if (is.length==0)
        return obj;
    else
        return index(obj[is[0]],is.slice(1), value);
}

function renderString(str,obj){
    return str.replace(/\$\{.+?\}/g,(match)=>{return index(obj,match)})
}

renderString('abc${a}asdas',{a:23,b:44}) //abc23asdas
renderString('abc${a.c}asdas',{a:{c:22,d:55},b:44}) //abc22asdas

【讨论】:

  • @s.meijer 你能详细说明一下吗?我正在成功使用此代码。 jsfiddle.net/w3jx07vt
  • 更好的正则表达式将允许您不选择 ${} 字符。试试:/(?!\${)([^{}]*)(?=})/g
  • @Relic jsfiddle.net/w3jx07vt/2 我无法正常工作,请帮忙,我会更新我的帖子? :)
  • 所以你试图抓住它的方式实际上并没有多大帮助,我最终做了一个字符串替换。而不是添加一个插值步骤,所以我可以将字符串用作 interp 或 string。不花哨,但它有效。
  • @EricHodonsky 你能详细说明“我试图抓住它的方式”吗?也许分享您的用例。上述大多数解决方案都侧重于代码生成,而我的解决方案不需要。这里的问题是 A) 访问变量(我不这样做,而是让用户传递它们),B) 查找替换名称的位置,C) 查找名称(在这种情况下是在对象上)。这根据 jsfiddle 有效。
【解决方案7】:

这里的问题是要有一个可以访问其调用者变量的函数。这就是为什么我们看到直接eval 被用于模板处理。一种可能的解决方案是生成一个函数,该函数采用由字典属性命名的形式参数,并以相同的顺序使用相应的值调用它。另一种方法是像这样简单:

var name = "John Smith";
var message = "Hello, my name is ${name}";
console.log(new Function('return `' + message + '`;')());

对于任何使用 Babel 编译器的人,我们需要创建一个闭包,它会记住创建它的环境:

console.log(new Function('name', 'return `' + message + '`;')(name));

【讨论】:

  • 你的第一个 sn-p 实际上比 eval 差,因为它只适用于全局 name 变量
  • @Bergi 您的声明是有效的 - 函数的范围将会丢失。我想为这个问题提供一个简单的解决方案,并提供一个简化的例子来说明可以做什么。人们可以简单地提出以下解决问题:var template = function() { var name = "John Smith"; var message = "Hello, my name is ${name}"; this.local = new Function('return ' + message + ';')();}
  • 不,这正是 起作用的 - new Function 无法访问 template 函数中的 var name
  • 第二个片段解决了我的问题...来自我的投票!谢谢,这有助于解决我们在动态路由到 iframe 时遇到的临时问题 :)
  • 你能解释一下吗,anyone using Babel compiler we need to create closure which remembers the environment in which it was created
【解决方案8】:

与 Daniel 的回答(和 s.meijer 的 gist)类似,但更具可读性:

const regex = /\${[^{]+}/g;

export default function interpolate(template, variables, fallback) {
    return template.replace(regex, (match) => {
        const path = match.slice(2, -1).trim();
        return getObjPath(path, variables, fallback);
    });
}

//get the specified property or nested property of an object
function getObjPath(path, obj, fallback = '') {
    return path.split('.').reduce((res, key) => res[key] || fallback, obj);
}

注意:这略微改进了 s.meijer 的原始版本,因为它不会匹配 ${foo{bar} 之类的内容(正则表达式只允许在 ${} 中使用非大括号字符)。


更新:有人问我使用这个的例子,所以你去:

const replacements = {
    name: 'Bob',
    age: 37
}

interpolate('My name is ${name}, and I am ${age}.', replacements)

【讨论】:

  • 你能发布一个实际使用这个的例子吗?这个 javascript 有点超出我的想象。我建议使用/\$\{(.*?)(?!\$\{)\}/g 的正则表达式(用于处理嵌套花括号)。我有一个可行的解决方案,但我不确定它是否像你的那样便携,所以我很想看看应该如何在页面中实现它。我的也使用eval()
  • 我继续并发布了一个答案,我希望您能就如何使其更安全和更注重性能提供反馈:stackoverflow.com/a/48294208
  • @RegularJoe 我添加了一个示例。我的目标是保持简单,但你是对的,如果你想处理嵌套的花括号,你需要更改正则表达式。但是,在评估常规字符串时,我想不出一个用例,就好像它是一个模板文字(这个函数的全部目的)。你想到了什么?
  • 另外,我既不是性能专家也不是安全专家;我的答案实际上只是结合了之前的两个答案。但我要说的是,使用eval 会让您更容易面对可能导致安全问题的错误,而我的版本所做的只是从点分隔路径中查找对象上的属性,这应该是安全的。
【解决方案9】:

我喜欢 s.meijer 的回答,并根据他的回答编写了我自己的版本:

function parseTemplate(template, map, fallback) {
    return template.replace(/\$\{[^}]+\}/g, (match) => 
        match
            .slice(2, -1)
            .trim()
            .split(".")
            .reduce(
                (searchObject, key) => searchObject[key] || fallback || match,
                map
            )
    );
}

【讨论】:

  • 整洁!真的很整洁!
  • 为什么是减速机?
  • 而不是searchObject[key],我不得不使用searchObject.hasOwnProperty(key) 来支持虚假值。
【解决方案10】:

@Mateusz Moska,解决方案效果很好,但是当我在 React Native(构建模式)中使用它时,它会抛出一个错误:Invalid character '`',虽然它在我运行它时可以工作调试模式。

所以我用正则表达式写下了我自己的解决方案。

String.prototype.interpolate = function(params) {
  let template = this
  for (let key in params) {
    template = template.replace(new RegExp('\\$\\{' + key + '\\}', 'g'), params[key])
  }
  return template
}

const template = 'Example text: ${text}',
  result = template.interpolate({
    text: 'Foo Boo'
  })

console.log(result)

演示: https://es6console.com/j31pqx1p/

注意:由于我不知道问题的根本原因,我在 react-native repo https://github.com/facebook/react-native/issues/14107 中提出了一张票,以便他们能够修复/指导我差不多:)

【讨论】:

  • 这确实支持包含反引号字符的模板。但是,与其尝试发明模板模式,不如只使用using mustache or similar。根据您的模板的复杂程度,这是一种不考虑极端情况的蛮力方法 - 密钥可能包含特殊的正则表达式模式。
【解决方案11】:

可以使用字符串原型,例如

String.prototype.toTemplate=function(){
    return eval('`'+this+'`');
}
//...
var a="b:${b}";
var b=10;
console.log(a.toTemplate());//b:10

但原问题的答案是不可能的。

【讨论】:

    【解决方案12】:

    我需要这种方法并支持 Internet Explorer。事实证明,即使 IE11 也不支持反引号。还;使用 eval 或等效的 Function 感觉不对。

    对于注意到的人;我也使用反引号,但是这些反引号会被 babel 等编译器删除。其他人建议的方法取决于它们的运行时。如前所述;这是 IE11 及更低版本的问题。

    所以这就是我想出的:

    function get(path, obj, fb = `$\{${path}}`) {
      return path.split('.').reduce((res, key) => res[key] || fb, obj);
    }
    
    function parseTpl(template, map, fallback) {
      return template.replace(/\$\{.+?}/g, (match) => {
        const path = match.substr(2, match.length - 3).trim();
        return get(path, map, fallback);
      });
    }
    

    示例输出:

    const data = { person: { name: 'John', age: 18 } };
    
    parseTpl('Hi ${person.name} (${person.age})', data);
    // output: Hi John (18)
    
    parseTpl('Hello ${person.name} from ${person.city}', data);
    // output: Hello John from ${person.city}
    
    parseTpl('Hello ${person.name} from ${person.city}', data, '-');
    // output: Hello John from -
    

    【讨论】:

    • "使用 eval 或它的等效函数感觉不对。" ......是的......我同意,但我认为这是极少数可以说“mmhkay,让我们使用它”的用例之一。请检查jsperf.com/es6-string-tmpl——这是我的实际用例。使用您的函数(与我的正则表达式相同)和我的函数(eval + 字符串文字)。谢谢! :)
    • @AndreaPuddu,你的表现确实更好。但话又说回来; IE 不支持模板字符串。所以eval('`' + taggedURL + '`') 根本行不通。
    • “似乎”更好我会说,因为它是单独测试的......该测试的唯一目的是使用eval查看潜在的性能问题。关于模板文字:感谢您再次指出这一点。我正在使用 Babel 转译我的代码,但我的函数显然仍然无法正常工作?
    【解决方案13】:

    我目前无法评论现有答案,因此我无法直接评论 Bryan Raynor 的出色回应。因此,此响应将通过稍微更正来更新他的答案。

    简而言之,他的函数并没有真正缓存创建的函数,所以它总是会重新创建,不管它之前是否见过模板。这是更正后的代码:

        /**
         * Produces a function which uses template strings to do simple interpolation from objects.
         * 
         * Usage:
         *    var makeMeKing = generateTemplateString('${name} is now the king of ${country}!');
         * 
         *    console.log(makeMeKing({ name: 'Bryan', country: 'Scotland'}));
         *    // Logs 'Bryan is now the king of Scotland!'
         */
        var generateTemplateString = (function(){
            var cache = {};
    
            function generateTemplate(template){
                var fn = cache[template];
    
                if (!fn){
                    // Replace ${expressions} (etc) with ${map.expressions}.
    
                    var sanitized = template
                        .replace(/\$\{([\s]*[^;\s\{]+[\s]*)\}/g, function(_, match){
                            return `\$\{map.${match.trim()}\}`;
                        })
                        // Afterwards, replace anything that's not ${map.expressions}' (etc) with a blank string.
                        .replace(/(\$\{(?!map\.)[^}]+\})/g, '');
    
                    fn = cache[template] = Function('map', `return \`${sanitized}\``);
                }
    
                return fn;
            };
    
            return generateTemplate;
        })();
    

    【讨论】:

      【解决方案14】:

      仍然是动态的,但似乎比仅使用裸 eval 更受控制:

      const vm = require('vm')
      const moment = require('moment')
      
      
      let template = '### ${context.hours_worked[0].value} \n Hours worked \n #### ${Math.abs(context.hours_worked_avg_diff[0].value)}% ${fns.gt0(context.hours_worked_avg_diff[0].value, "more", "less")} than usual on ${fns.getDOW(new Date())}'
      let context = {
        hours_worked:[{value:10}],
        hours_worked_avg_diff:[{value:10}],
      
      }
      
      
      function getDOW(now) {
        return moment(now).locale('es').format('dddd')
      }
      
      function gt0(_in, tVal, fVal) {
        return _in >0 ? tVal: fVal
      }
      
      
      
      function templateIt(context, template) {
        const script = new vm.Script('`'+template+'`')
        return script.runInNewContext({context, fns:{getDOW, gt0 }})
      }
      
      console.log(templateIt(context, template))
      

      https://repl.it/IdVt/3

      【讨论】:

        【解决方案15】:

        这个解决方案在没有 ES6 的情况下也可以工作:

        function render(template, opts) {
          return new Function(
            'return new Function (' + Object.keys(opts).reduce((args, arg) => args += '\'' + arg + '\',', '') + '\'return `' + template.replace(/(^|[^\\])'/g, '$1\\\'') + '`;\'' +
            ').apply(null, ' + JSON.stringify(Object.keys(opts).reduce((vals, key) => vals.push(opts[key]) && vals, [])) + ');'
          )();
        }
        
        render("hello ${ name }", {name:'mo'}); // "hello mo"
        

        注意:Function 构造函数总是在全局范围内创建,这可能会导致全局变量被模板覆盖,例如render("hello ${ someGlobalVar = 'some new value' }", {name:'mo'});

        【讨论】:

          【解决方案16】:

          你应该试试这个来自 github 的 Andrea Giammarchi 的微型 JS 模块: https://github.com/WebReflection/backtick-template

          /*! (C) 2017 Andrea Giammarchi - MIT Style License */
          function template(fn, $str, $object) {'use strict';
            var
              stringify = JSON.stringify,
              hasTransformer = typeof fn === 'function',
              str = hasTransformer ? $str : fn,
              object = hasTransformer ? $object : $str,
              i = 0, length = str.length,
              strings = i < length ? [] : ['""'],
              values = hasTransformer ? [] : strings,
              open, close, counter
            ;
            while (i < length) {
              open = str.indexOf('${', i);
              if (-1 < open) {
                strings.push(stringify(str.slice(i, open)));
                open += 2;
                close = open;
                counter = 1;
                while (close < length) {
                  switch (str.charAt(close++)) {
                    case '}': counter -= 1; break;
                    case '{': counter += 1; break;
                  }
                  if (counter < 1) {
                    values.push('(' + str.slice(open, close - 1) + ')');
                    break;
                  }
                }
                i = close;
              } else {
                strings.push(stringify(str.slice(i)));
                i = length;
              }
            }
            if (hasTransformer) {
              str = 'function' + (Math.random() * 1e5 | 0);
              if (strings.length === values.length) strings.push('""');
              strings = [
                str,
                'with(this)return ' + str + '([' + strings + ']' + (
                  values.length ? (',' + values.join(',')) : ''
                ) + ')'
              ];
            } else {
              strings = ['with(this)return ' + strings.join('+')];
            }
            return Function.apply(null, strings).apply(
              object,
              hasTransformer ? [fn] : []
            );
          }
          
          template.asMethod = function (fn, object) {'use strict';
            return typeof fn === 'function' ?
              template(fn, this, object) :
              template(this, fn);
          };
          

          演示(以下所有测试都返回 true):

          const info = 'template';
          // just string
          `some ${info}` === template('some ${info}', {info});
          
          // passing through a transformer
          transform `some ${info}` === template(transform, 'some ${info}', {info});
          
          // using it as String method
          String.prototype.template = template.asMethod;
          
          `some ${info}` === 'some ${info}'.template({info});
          
          transform `some ${info}` === 'some ${info}'.template(transform, {info});
          

          【讨论】:

            【解决方案17】:

            我制作了自己的解决方案,将类型描述为函数

            export class Foo {
            ...
            description?: Object;
            ...
            }
            
            let myFoo:Foo = {
            ...
              description: (a,b) => `Welcome ${a}, glad to see you like the ${b} section`.
            ...
            }
            

            然后这样做:

            let myDescription = myFoo.description('Bar', 'bar');
            

            【讨论】:

              【解决方案18】:

              因为我们正在重新发明轮子,这将是 javascript 中一个可爱的功能。

              我使用eval(),它不安全,但javascript 不安全。我欣然承认我在 javascript 方面并不出色,但我有需要,我需要一个答案,所以我做了一个。

              我选择使用@ 而不是$ 对我的变量进行样式化,特别是因为我想使用文字的多行特性而不评估直到它准备好。所以变量语法是@{OptionalObject.OptionalObjectN.VARIABLE_NAME}

              我不是 javascript 专家,所以我很乐意听取改进建议,但是...

              var prsLiteral, prsRegex = /\@\{(.*?)(?!\@\{)\}/g
              for(i = 0; i < myResultSet.length; i++) {
                  prsLiteral = rt.replace(prsRegex,function (match,varname) {
                      return eval(varname + "[" + i + "]");
                      // you could instead use return eval(varname) if you're not looping.
                  })
                  console.log(prsLiteral);
              }
              

              下面是一个非常简单的实现

              myResultSet = {totalrecords: 2,
              Name: ["Bob", "Stephanie"],
              Age: [37,22]};
              
              rt = `My name is @{myResultSet.Name}, and I am @{myResultSet.Age}.`
              
              var prsLiteral, prsRegex = /\@\{(.*?)(?!\@\{)\}/g
              for(i = 0; i < myResultSet.totalrecords; i++) {
                  prsLiteral = rt.replace(prsRegex,function (match,varname) {
                      return eval(varname + "[" + i + "]");
                      // you could instead use return eval(varname) if you're not looping.
                  })
                  console.log(prsLiteral);
              }

              在我的实际实现中,我选择使用@{{variable}}。再来一组牙套。出乎意料地不太可能遇到这种情况。正则表达式看起来像/\@\{\{(.*?)(?!\@\{\{)\}\}/g

              为了便于阅读

              \@\{\{    # opening sequence, @{{ literally.
              (.*?)     # capturing the variable name
                        # ^ captures only until it reaches the closing sequence
              (?!       # negative lookahead, making sure the following
                        # ^ pattern is not found ahead of the current character
                \@\{\{  # same as opening sequence, if you change that, change this
              )
              \}\}      # closing sequence.
              

              如果您没有使用正则表达式的经验,一个非常安全的规则是转义每个非字母数字字符,并且不要永远不必要地转义字母,因为许多转义字母对几乎所有人都有特殊含义正则表达式的味道。

              【讨论】:

                【解决方案19】:

                我意识到我迟到了,但你可以:

                const a =  (b) => `b:${b}`;
                
                let b = 10;
                console.log(a(b)); // b:10

                【讨论】:

                • 这不会“将模板字符串创建为普通字符串”,这是 OP 中的要求之一。
                猜你喜欢
                • 1970-01-01
                • 2022-11-28
                • 2015-03-02
                相关资源
                最近更新 更多