文字列をテンプレート文字列に変換する


147

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

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

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

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

なしevalnew Functionおよび動的コード生成の他の手段?


5
これを達成する方法を見つけましたか?私はいつかそれをする必要があるかもしれません、そしてあなたが何に着いたかを知りたいと思っています。
ブライアンレイナー、2015

@BryanRaynerは、jsプログラムがREST APIからデータを取得しようとしていると言います。URLはconfig.jsファイルに文字列「/ resources / <resource_id> / update /」としてあり、プログラムから「resource_id」を動的に配置します。そのURLを分割して別の領域に保存したい場合を除き、何らかの文字列テンプレート処理が必要です。
Ryu_hayabusa 16


Evalを使用する代わりに、Evalを正規表現に使用することをお勧めします。これはお勧めできません。強くお勧めしません。したがって、使用しないでください。developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…!b = 10とします。let a = "b:$ {b}"; let response = a.replace(/ \ $ {\ w +} /、b); conssole.log(response);
Vijay Palaskar

回答:


79

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

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

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

7
evalは安全ではないので、動的コード生成の他の手段もそうです
KOLANICH

8
@KOLANICH特にその場合- a文字列内の引用符をエスケープすると、安全性が大幅に低下しますlet tpl = eval('`'+a.replace(/`/g,'\\`')+'`');。さらに重要なのは、evalコンパイラがコードを最適化できないようにすることです。しかし、私はそれはこの質問には無関係であると思います。
alexpods 2015年

3
実際、テンプレート文字列内で関数を実行することもできます。
KOLANICH 2015年

9
@KOLANICH嫌いevalです。ただし、テンプレートリテラル自体がの形式であることを忘れないでくださいeval。2つの例:var test = Result: ${alert('hello')}; var test = Result: ${b=4}; どちらも、スクリプトのコンテキストで任意のコードを実行することになります。任意の文字列を許可する場合は、許可することもできevalます。
Manngo

6
注意してください。babelのようなものはこれをトランスパイルしないため、このコードはIEでは機能しません
cgsd

79

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

更新 lodashの依存関係を削除しました。ES6にはキーと値を取得するための同等のメソッドがあります。


1
こんにちは、あなたのソリューションはうまく機能しますが、React Native(ビルドモード)で使用すると、エラーがスローされます:無効な文字 '`'ですが、デバッグモードで実行すると機能します。バベルの問題、何か助けのように見えますか?
Mohit Pandey

@MohitPandey PhantomJSの下でこのコードのテストを実行していて、Chromeの下を通過していたときに、同じエラーが発生しました。その場合は、ES6のサポートが改善されたPhantomJSの新しいベータ版があると思います。インストールしてみてください。
Mateusz Moska

1
残念ながら、それは機能せず、私は同じものの正規表現を書き留めました。回答としても追加されました。
Mohit Pandey

このソリューションは、テンプレート文字列にバックティック「 `」文字が存在しない場合にのみ機能します
SliverNinja-MSFT

私はそれをしようとすると、私は得ましたReferenceError: _ is not defined。それはES6ではなくlodash特定のコードですか、それとも...?
xpt '19

29

ここであなたが求めているもの:

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

(パワーおよび安全性の面で)まったく同じevalです。コードを含む文字列を取得し、そのコードを実行する機能。また、実行されたコードが呼び出し元の環境のローカル変数を参照する機能。

JSでは、関数がでない限り、関数が呼び出し元のローカル変数を参照する方法はありませんeval()。それもFunction()できません。


JavaScriptに「テンプレート文字列」と呼ばれるものがあると聞いたら、Mustacheのような組み込みのテンプレートライブラリであると考えるのは自然です。そうではありません。それは主に単なるJSの文字列補間と複数行文字列です。これはしばらくの間、よくある誤解になると思います。:(


2
TBHは私が思っていたものです。とても便利でした。
ブライアンレイナー

これは(まだ)機能しますか?私は取得していますtemplate is not a function
IonicăBizău

2
この回答の上部にあるコードブロックは、質問の引用です。それは動作しません。
Jason Orendorff

27

いいえ、動的なコード生成なしでこれを行う方法はありません。

ただし、内部でテンプレート文字列を使用して、通常の文字列を値のマップを提供できる関数に変換する関数を作成しました。

テンプレート文字列要旨を生成

/**
 * 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ソリューションの代わりにこれを使用しました。
seangwright 2016

1
すべてのテンプレートがvar test = generateTemplateString('/api/${param1}/${param2}/') console.log(test({param1: 'bar', param2: 'foo'}))返される場合は機能しません/api/bar//
Guillaume Vincent

ありがとう、修正しました。正規表現には、2つの一致があったはずの$ {param1} / $ {param2}の単一の一致が含まれていました。
ブライアンレイナー

バックティックのサポートがないため、IE11ではこれは機能しません。
s.meijer 2017年

1
もちろん、テンプレート文字列がブラウザでサポートされていない場合、このメソッドは機能しません。サポートされていないブラウザーでテンプレート文字列を使用する場合は、TypeScriptなどの言語、またはBabelなどのトランスパイラーを使用することをお勧めします。これが、ES6を古いブラウザに組み込む唯一の方法です。
ブライアンレイナー2017年

9

TLDR:https ://jsfiddle.net/w3jx07vt/

誰もが変数へのアクセスについて心配しているようですが、単に変数を渡さないのはなぜですか?呼び出し側で変数のコンテキストを取得して渡すのはそれほど難しいことではないと私は確信しています。このhttps://stackoverflow.com/a/6394168/6563504を使用して、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

@ s.meijerについて詳しく教えてください。このコードを正常に使用しています。jsfiddle.net/w3jx07vt
1

1
より良い正規表現を使用すると、${}文字を選択できなくなります。試してみてください/(?!\${)([^{}]*)(?=})/g
エリックホドンスキー2017

@Relic jsfiddle.net/w3jx07vt/2私はそれを機能させることができませんでした。手を貸してくれたら投稿を更新しますか?:)
M3D 2017

だからあなたがそれをつかもうとしている方法はこれは実際にはあまり役に立たないので、代わりに文字列の置換を行うことになりました。補間のステップを追加する代わりに、文字列をinterpまたはstringとして使用できます。派手ではありませんが、うまくいきました。
エリックホドンスキー2017

8

ここでの問題は、呼び出し元の変数にアクセスできる関数を持つことです。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));

最初のスニペットはeval、グローバルname変数でのみ機能するため、実際よりも悪い
Bergi

@Bergiステートメントは有効です-関数のスコープが失われます。私は問題の簡単な解決策を提示したかったし、何ができるかの簡単な例を提供しました。この問題を克服するために次のことを考え出すだけです。 var template = function() { var name = "John Smith"; var message = "Hello, my name is ${name}"; this.local = new Function('return '+メッセージ+';')();}
ディディンコ

いや、正確に何だろうということではない仕事- new Functionにアクセスすることはできませんvar nametemplate機能。
Bergi、2015年

2番目の切り取りで問題が解決しました...私からの賛成票!おかげで、これはiframeへの動的ルーティングで発生していた一時的な問題の解決に役立ちました:)
Kris Boyd

7

ここには多くの優れたソリューションが掲載されていますが、ES6のString.rawメソッドを利用するソリューションはまだありません。これが私の貢献です。これには、渡されたオブジェクトからのプロパティのみを受け入れるという重要な制限があります。つまり、テンプレートでのコード実行は機能しません。

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. 文字列を非引数のテキスト部分に分割します。正規表現を参照してください。
    parts: ["Hello, ", "! Are you ", " years old?"]
  2. 文字列をプロパティ名に分割します。一致が失敗した場合は空の配列。
    args: ["name", "age"]
  3. objプロパティ名でパラメータをマッピングします。ソリューションは、浅い1レベルのマッピングによって制限されます。未定義の値は空の文字列に置き換えられますが、他の偽の値は受け入れられます。
    parameters: ["John Doe", 18]
  4. String.raw(...)結果を利用して返します。

好奇心から、String.rawが実際にここで提供する値は何ですか?文字列を解析し、置換が何であるかを追跡するすべての作業を行っているようです。これは単純に.replace()繰り返し呼び出すこととは大きく異なりますか?
スティーブベネット

フェアポイント、@ SteveBennett。通常の文字列をテンプレート文字列に変換する際にいくつかの問題があり、生のオブジェクトを自分で構築することで解決策を見つけました。String.rawを連結メソッドに削減すると思いますが、それは非常にうまく機能すると思います。でも、私はで良い解決策を見たい.replace()と思っています:)読みやすさが重要だと思うので、自分で正規表現を使用しているときは、それらをすべて
わかり

6

ダニエルの答え(およびs.meijerの要点)に似ていますが、より読みやすくなっています。

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
定例Joe

@RegularJoe例を追加しました。私の目標はそれを単純に保つことでしたが、ネストされた中括弧を処理したい場合は、正規表現を変更する必要があるというのは正しいです。ただし、通常の文字列をテンプレートリテラル(この関数の目的全体)であるかのように評価するときの使用例は思いつきません。何を思っていたんだ?
Matt Browne

また、私はパフォーマンスの専門家でもセキュリティの専門家でもありません。私の答えは、実際には以前の2つの答えを組み合わせるだけです。しかし、私が使用すると、evalセキュリティ上の問題を引き起こす可能性のある間違いに対してよりオープンになります。一方、私のバージョンでは、ドットで区切られたパスからオブジェクトのプロパティを検索するだけなので、安全であると言えます。
Matt Browne

5

たとえば、文字列プロトタイプを使用できます

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

しかし、元の質問の答えは方法ではありません。


5

私は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
            )
    );
}

1
きちんと!本当にきちんと!
xpt '19

4

Internet Explorerをサポートするこの方法が必要でした。バックティックはIE11でもサポートされていないことがわかりました。また; 使用evalまたは同等のものFunctionは正しくありません。

気づいた方のために; 私もバックティックを使用していますが、これらはバベルのようなコンパイラによって削除されます。他のものによって提案された方法は、ランタイムに依存します。前に言ったように; これは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またはそれと同等のFunctionを使用するのは正しくありません。」...ええ...同意しますが、これは「うーん、使ってみよう」と言える非常に少数のユースケースの1つだと思います。jsperf.com/es6-string-tmplを確認してください-これは私の実用的な使用例です。あなたの関数(私のものと同じ正規表現で)と私のもの(eval +文字列リテラル)を使う。ありがとう!:)
Andrea Puddu 2017

@AndreaPuddu、あなたのパフォーマンスは確かに優れています。しかし、その後再び。IEではテンプレート文字列はサポートされていません。したがって、eval('`' + taggedURL + '`')単に機能しません。
s.meijer 2017

単独でテストされているので、私は「よりよく見える」と思います。そのテストの唯一の目的は、を使用して潜在的なパフォーマンスの問題を確認することevalでした。テンプレートリテラルについて:再度指摘していただきありがとうございます。😐私は私のコードをtranspileするバベルを使用していますが、私の機能はまだ明らかに動作しません
アンドレアPuddu

3

現在、私は既存の回答にはコメントできません。そのため、ブライアンレイナーの優れた反応に直接コメントすることはできません。したがって、この応答は彼の答えをわずかに修正して更新します。

つまり、彼の関数は作成された関数を実際にキャッシュすることができないため、以前にテンプレートを見たことがあるかどうかに関係なく、常に再作成されます。修正されたコードは次のとおりです。

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

3

@Mateusz Moska、ソリューションはうまく機能しますが、React Native(ビルドモード)で使用すると、エラーがスローされます:無効な文字 '`'ですが、デバッグモードで実行すると機能します。

だから私は正規表現を使用して自分のソリューションを書き留めました。

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リポジトリ(https://github.com/facebook/react-native/issues/14107)でチケットを作成しました。同じことを修正/ガイドしてください:)


これは、バックティック文字を含むテンプレートをサポートします。ただし、テンプレートパターンを考案するよりも、口ひげなどを使用するほうがよいでしょう。テンプレートの複雑さに応じて、これはエッジケースを考慮しないブルートフォースアプローチです。キーには特別な正規表現パターンを含めることができます。
SliverNinja-MSFT 2017年

2

まだ動的ですが、裸の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


1

このソリューションは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'});


0

私たちは、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}}。中括弧のもう1つのセット。予期せずにそれに遭遇する可能性はありません。そのための正規表現は次のようになります/\@\{\{(.*?)(?!\@\{\{)\}\}/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.

正規表現に慣れていない場合、かなり安全なルールは、英数字以外のすべての文字をエスケープすることです。エスケープされた文字の多くは、事実上すべての正規表現に対して特別な意味を持つため、文字を不必要にエスケープしないください。


0

Andrea Giammarchiによるgithubのこの小さな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});

0

説明を関数として使用してタイプを行う独自のソリューションを作成しました

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');

0

より良いevalを使用する代わりに、正規表現を使用します

Evalは推奨されておらず、お勧めしません。使用しないでください(mdn eval)。

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

let response = a.replace(/\${\w+}/ ,b);
conssole.log(response);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.