195

テンプレート文字列を通常の文字列として作成することは可能ですか?

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

それをテンプレート文字列に変換し、

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

なしevalで、new Functionおよび動的コード生成の他の手段はありますか?

4

19 に答える 19

129

私のプロジェクトでは、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);

于 2016-12-07T11:07:15.220 に答える
105

テンプレート文字列はb動的に (実行時に) 変数への参照を取得する必要があるため、答えは:いいえ、動的コ​​ード生成なしでは不可能です。

しかし、evalそれは非常に簡単です:

let tpl = eval('`'+a+'`');
于 2015-03-21T12:36:46.823 に答える
12

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

変数へのアクセスについては、誰もが心配しているようです。なぜそれらを渡さないのですか?呼び出し元で変数コンテキストを取得して渡すのはそれほど難しくないと確信しています。ninjagecko の回答を使用 して、obj から小道具を取得します。

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
于 2017-01-09T02:58:19.137 に答える
10

ここでの問題は、呼び出し元の変数にアクセスできる関数を用意することです。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));
于 2015-11-28T11:10:09.340 に答える
3

現在、既存の回答についてコメントすることはできないため、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;
    })();
于 2016-12-04T16:33:29.747 に答える