是否可以创建一个模板字符串作为一个普通的字符串,

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

然后把它转换成一个模板字符串,

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

没有eval, new Function和其他动态代码生成的手段?


当前回答

我知道我来晚了,但你可以:

Const a = (b) => ' b:${b} '; 令b = 10; console.log (a (b));/ / b: 10

其他回答

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

但是,使用eval非常简单:

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

我目前不能评论现有的答案,所以我无法直接评论布莱恩·雷诺的出色回答。因此,这个回答将会更新他的答案,稍微修正一下。

简而言之,他的函数实际上没有缓存创建的函数,所以它总是重新创建,不管之前是否见过模板。以下是修正后的代码:

    /**
     * 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;
    })();

我需要Internet Explorer支持这种方法。事实证明,甚至连IE11都不支持后勾。也;使用eval或它的等效函数感觉不对。

为了那个注意到的人;我也使用反撇号,但是这些被像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 -

你想要的是:

//从问题中引用的非工作代码 让b = 10; console.log (a.template ()); / / b: 10

与eval完全相同(就功能和安全而言):获取包含代码的字符串并执行该代码的能力;执行的代码还可以看到调用者环境中的局部变量。

在JS中,函数无法看到调用者中的局部变量,除非该函数是eval()。甚至Function()也做不到。


当您听说JavaScript中出现了所谓的“模板字符串”时,很自然地认为这是一个内置的模板库,就像Mustache一样。它不是。它主要是字符串插值和JS的多行字符串。不过,我认为这在一段时间内将是一个普遍的误解。:(

有很多好的解决方案张贴在这里,但没有一个利用ES6字符串。原始的方法。这是我的贡献。它有一个重要的限制,它只接受传入对象的属性,这意味着模板中的代码执行将不起作用。

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?

将字符串拆分为非参数的文本部分。看到正则表达式。 部分:[“你好,”,“!”你多大了?”) 将字符串拆分为属性名。如果匹配失败则为空数组。 参数:["name", "age"] 通过属性名映射obj中的参数。解决方案受限于浅的一级映射。未定义的值用空字符串代替,但接受其他假值。 参数:["John Doe", 18] 使用String.raw(…)并返回结果。