JavaScriptで文字列補間を実行するにはどうすればよいですか?


536

このコードを考えてみましょう:

var age = 3;

console.log("I'm " + age + " years old!");

文字列の連結以外に、変数の値を文字列に挿入する方法は他にありますか?


7
CoffeeScriptをチェックアウトできます:coffeescript.org
dennismonsewicz

1
他の人が示したように、あなたが使用している方法それを行う最も簡単な方法です。文字列内の変数を参照できるようにしたいのですが、JavaScriptでは連結(または他の検索/置換アプローチ)を使用する必要があります。あなたや私などの人々は、おそらく私たち自身のためにPHPにあまりにも執着しています。
Lev

4
Underscore.js テンプレートを
Jahan

2
連結は補間ではなく、ユーザーは補間の方法を尋ねました。Levが最終的に答えを出したと思います。つまり、ネイティブJSでこれを行う方法はありません。これが本当の質問ではない理由がわかりません。
gitb 2014年

4
答えてもらえれば、新しいインタープリッター(2015 FFとChromeはすでにサポートしています)向けのソリューションがあります:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 。例えば。Show GRAPH of : ${fundCode}-${funcCode} 私を取得しますShow GRAPH of : AIP001-_sma (文字列1.の周りにバックティックを使用します...ここには表示されないようです)
Marcos

回答:


537

ES6以降、テンプレートリテラルを使用できます。

const age = 3
console.log(`I'm ${age} years old!`)

PSバックティックの使用に注意してください``


3
彼らがなぜこれをバッククォートで行ったのか疑問に思っています、「$ {age}」は補間を行うのに十分ではないでしょうか?
レモネードを笑う

5
@LaughingLemonade下位互換性。その方法で実装された場合、その形式で文字列を出力する既存のコードはすべて失敗します。
thefourtheye 2018

1
@ジョナサン私はいつも意味のある文字としてバックティックを嫌います。しかし、その理由が普遍的なものなのか、自分の言語のキーボードレイアウトだけに当てはまるのかはわかりません。バックティックは、次の文字まで書き込まれるのを待つ特殊な種類の文字であり、書き込むには2回押す必要があります(この時点で2つ書き込む)。これは、「e」などの一部の文字がそれらと相互作用するためです。彼らと一緒に「こんにちは」と書こうとすると、「llello」が表示されます。また、 'とは異なり、タイプにシフトする必要があるため、やや煩わしい場所に配置されます(shift + forwardtickもこのような特別な先読み文字です)。
felix

@felixは、キーボードレイアウトに固有の考え方です。あなたが説明しているものは「デッドキー」と呼ばれています。それらはノルウェー語のキーボードレイアウト(出身地)にも存在します。これは、すべてのプログラミングで米国のキーボードレイアウトに切り替える理由の一部です。(他にも多くの文字があります。たとえば、[と]は、USキーボードでもずっと簡単です。)
Eivind Eklund

239

tl; dr

必要に応じて、ECMAScript 2015のテンプレート文字列リテラルを使用します。

説明

ECMAScript 5仕様のとおり、直接実行する方法はありませんが、ECMAScript 6にはテンプレート文字列があり、仕様の草案では準リテラルとしても知られていました。次のように使用します。

> var n = 42;
undefined
> `foo${n}bar`
'foo42bar'

内では任意の有効なJavaScript式を使用できます{}。例えば:

> `foo${{name: 'Google'}.name}bar`
'fooGooglebar'
> `foo${1 + 3}bar`
'foo4bar'

もう1つ重要なことは、複数行の文字列についてもう心配する必要がないことです。単純に次のように書くことができます

> `foo
...     bar`
'foo\n    bar'

注: io.js v2.4.0を使用して、上記のすべてのテンプレート文字列を評価しました。また、最新のChromeを使用して、上記の例をテストすることもできます。

注: ES6仕様は最終決定されましたが、すべての主要なブラウザーでまだ実装されていません。Mozilla Developer Networkページ
よると、これは、Firefox 34、Chrome 41、Internet Explorer 12以降の基本的なサポートのために実装される予定です。Opera、Safari、またはInternet Explorerのユーザーで、これに興味がある場合、このテストベッドは、誰もがこれをサポートするまで、遊ぶために使用できます。


3
babeljsを使用する場合に使用できるので、コードベースに導入し、サポートする必要のあるブラウザーがそれを実装したら、後でトランスパイレーション手順を削除できます。
ivarni 2015年

標準の文字列をテンプレート文字列リテラルに変換する方法はありますか?たとえば、表示のために値を補間する必要がある変換テーブルを含むjsonファイルがある場合はどうでしょうか。最初の解決策はおそらくこの状況でうまく機能すると思いますが、新しい文字列テンプレートの構文は一般的に気に入っています。
2016

これはjs文字列補間の最初の検索結果の1つであるため、一般的な可用性を反映するように更新できると便利です。「直接実行する方法はありません」は、ほとんどのブラウザではおそらくもう当てはまりません。
Felix Dombek

2
聴衆の視力が悪いので、「キャラクターは違う」。これを機能させるのに問題がある場合は、重大な引用(傾斜した引用、逆引用)en.wikipedia.org/wiki/Grave_accentを使用してください 。キーボードの左上にあります:)
Quincy

@Quincy Macキーボードの左下-バックティックとも呼ばれ
ます

192

Douglas CrockfordのRemedial JavaScriptにはString.prototype.supplant関数が含まれています。短く、使いやすく、使いやすいです。

String.prototype.supplant = function (o) {
    return this.replace(/{([^{}]*)}/g,
        function (a, b) {
            var r = o[b];
            return typeof r === 'string' || typeof r === 'number' ? r : a;
        }
    );
};

// Usage:
alert("I'm {age} years old!".supplant({ age: 29 }));
alert("The {a} says {n}, {n}, {n}!".supplant({ a: 'cow', n: 'moo' }));

Stringのプロトタイプを変更したくない場合は、いつでもスタンドアロンに適合させるか、他の名前空間などに配置できます。


103
注:これは、連結よりも10倍遅く実行されます。
cllpse

36
さらに、約3倍のキーストロークとバイト数が必要です。
ma11hew28

8
@roosteronacid-あなたはその速度低下についていくつかの視点を与えることができますか?同様に、0.01秒から0.1秒(重要)または0.000000001秒から0.00000001秒(無関係)?
chris

16
@george:私のマシンでのクイックテストでは、「牛はmoo、moo、moo!」と7312 nsを示しました。渡されたオブジェクトから変数を引き出し、それらをテンプレート文字列の定数部分と連結するプリコンパイルされた関数に対して、Crockfordのメソッドと111 nsを使用します。これは、クロム21だった
ジョージ

13
:またはのようにそれを使用"The {0} says {1}, {1}, {1}!".supplant(['cow', 'moo'])
ロバート・マッサ

54

注意事項:独自の区切り文字をエスケープできないテンプレートシステムは避けてください。たとえば、supplant()ここに記載されている方法を使用して以下を出力する方法はありません。

「{age}変数のおかげで3歳です。」

単純な補間は小さな自己完結型のスクリプトで機能する可能性がありますが、深刻な使用を制限するこの設計上の欠陥がしばしば付属しています。私は正直に、次のようなDOMテンプレートを好みます。

<div> I am <span id="age"></span> years old!</div>

そしてjQuery操作を使用します: $('#age').text(3)

または、単に文字列の連結に飽き飽きしている場合は、常に代替の構文があります。

var age = 3;
var str = ["I'm only", age, "years old"].join(" ");

4
サイドノート:Array.join()直接(より遅い+(ノードと今日JSを実行するほとんど何を含んでV8を含んでいる)ブラウザエンジンは、大規模なそれを最適化しているとの違いの大きな取引はの賛成でありますので、スタイル)連結直接連結
pilau

1
supplantメソッドを使用すると、言及した文字列を生成できます。{token}は、データオブジェクトに呼び出されたメンバーが含まれている場合にのみ置き換えられますtoken-したがって、ageメンバーを持つデータオブジェクトを指定しない場合は問題ありません。
Chris Fewtrell、2014

1
クリス、それが解決策かどうかはわかりません。例を簡単に更新して、age変数と{age}文字列の両方を使用できます。テンプレートコピーテキストに基づいて変数に何を付けることができるかについて本当に心配したいですか?-また、この投稿以来、私はデータバインディングライブラリの大ファンになりました。RactiveJSのような一部のものは、可変スパンを伴うDOMからあなたを救います。そして口ひげとは異なり、それはページのその部分のみを更新します。
greg.kindel 2014年

3
あなたの主な答えは、質問にHTMLのタグが付けられていなくても、このJavaScriptがブラウザ環境で実行されていると想定しているようです。
キヤノン

2
に関する「注意事項」supplantは不当です"I am 3 years old thanks to my {age} variable.".supplant({}));。指定された文字列を正確に返します。指定された場合ageでも、印刷{して}使用できます{{age}}
le_m

23

sprintfライブラリ(完全なオープンソースのJavaScript sprintf実装)を試してください。例えば:

vsprintf('The first 4 letters of the english alphabet are: %s, %s, %s and %s', ['a', 'b', 'c', 'd']);

vsprintfは引数の配列を取り、フォーマットされた文字列を返します。


22

多くの言語でこのパターンを使用していますが、適切に実行する方法がわからないため、アイデアをすばやく取得したいと考えています。

// JavaScript
let stringValue = 'Hello, my name is {name}. You {action} my {relation}.'
    .replace(/{name}/g    ,'Indigo Montoya')
    .replace(/{action}/g  ,'killed')
    .replace(/{relation}/g,'father')
    ;

特に効率的ではありませんが、読みやすいと思います。それは常に機能し、常に利用可能です:

' VBScript
dim template = "Hello, my name is {name}. You {action} my {relation}."
dim stringvalue = template
stringValue = replace(stringvalue, "{name}"    ,"Luke Skywalker")     
stringValue = replace(stringvalue, "{relation}","Father")     
stringValue = replace(stringvalue, "{action}"  ,"are")

常に

* COBOL
INSPECT stringvalue REPLACING FIRST '{name}'     BY 'Grendel'
INSPECT stringvalue REPLACING FIRST '{relation}' BY 'Mother'
INSPECT stringvalue REPLACING FIRST '{action}'   BY 'did unspeakable things to'



6

文字列補間用の軽量JavaScriptモジュールであるkiwiを試してください。

できるよ

Kiwi.compose("I'm % years old!", [age]);

または

Kiwi.compose("I'm %{age} years old!", {"age" : age});

6

console.log出力で補間したい場合は、

console.log("Eruption 1: %s", eruption1);
                         ^^

ここで、%s「書式指定子」と呼ばれるものです。console.logこの種の補間サポートが組み込まれています。


1
これが唯一の正しい答えです。質問は、テンプレート文字列ではなく補間についてです。
sospedra 2018年

5

これは、オブジェクトに値を提供する必要があるソリューションです。オブジェクトをパラメーターとして指定しない場合、デフォルトでグローバル変数が使用されます。しかし、パラメータの使用に固執するほうがずっときれいです。

String.prototype.interpolate = function(props) {
    return this.replace(/\{(\w+)\}/g, function(match, expr) {
        return (props || window)[expr];
    });
};

// Test:

// Using the parameter (advised approach)
document.getElementById("resultA").innerText = "Eruption 1: {eruption1}".interpolate({ eruption1: 112 });

// Using the global scope
var eruption2 = 116;
document.getElementById("resultB").innerText = "Eruption 2: {eruption2}".interpolate();
<div id="resultA"></div><div id="resultB"></div>


3
使用しないでくださいevaleval悪です!
chris97ong 2014

5
@ chris97ongそれは「本当」ですが、少なくとも理由(「悪」は助けにはなりません)または代替ソリューションを提供してください。を使用する方法はほとんど常にありますがeval、そうでない場合もあります。たとえば、OPが現在のスコープを使用して補間する方法が必要な場合(たとえば、Groovy補間のように)ルックアップオブジェクトを渡さなくてevalも、必要になると確信しています。古い「eval is evil」に頼るだけではいけません。
Ian

1
evalを使用したり、使用するように提案したりしないでください
2015年

2
@hasenjこれが、私がそれを「最良のアイデアではないかもしれない」と述べ、代替方法を提供した理由です。しかし、残念ながら、evalスコープ内のローカル変数にアクセスする唯一の方法です。それはあなたの気持ちを傷つけるからといってそれを拒否しないでください。ところで、私はそれがより安全であるので、私も代替の方法を好みます、しかし、eval方法はOPの質問に正確に答えるものであり、それゆえ、それは答えにあります。
Lucas Trzesniewski、2015年

1
の問題evalは、別のスコープからvarにアクセスできないため、.interpolate呼び出しがグローバルではなく別の関数内にある場合、機能しないことです。
georg 2015

2

Greg Kindelの 2番目の答えを拡張すると、定型文の一部を削除する関数を記述できます。

var fmt = {
    join: function() {
        return Array.prototype.slice.call(arguments).join(' ');
    },
    log: function() {
        console.log(this.join(...arguments));
    }
}

使用法:

var age = 7;
var years = 5;
var sentence = fmt.join('I am now', age, 'years old!');
fmt.log('In', years, 'years I will be', age + years, 'years old!');

1

例を挙げて説明します。

function fullName(first, last) {
  let fullName = first + " " + last;
  return fullName;
}

function fullNameStringInterpolation(first, last) {
  let fullName = `${first} ${last}`;
  return fullName;
}

console.log('Old School: ' + fullName('Carlos', 'Gutierrez'));

console.log('New School: ' + fullNameStringInterpolation('Carlos', 'Gutierrez'));


1

ES6以降、オブジェクトキーで文字列補間を実行するSyntaxError: expected property name, got '${'場合、次のような操作を行うと、

let age = 3
let obj = { `${age}`: 3 }

代わりに以下を実行する必要があります。

let obj = { [`${age}`]: 3 }

1

@Chris Nielsenの投稿のES6バージョンにさらに置き換えます。

String.prototype.supplant = function (o) {
  return this.replace(/\${([^\${}]*)}/g,
    (a, b) => {
      var r = o[b];
      return typeof r === 'string' || typeof r === 'number' ? r : a;
    }
  );
};

string = "How now ${color} cow? {${greeting}}, ${greeting}, moo says the ${color} cow.";

string.supplant({color: "brown", greeting: "moo"});
=> "How now brown cow? {moo}, moo, moo says the brown cow."

0

古いブラウザでテンプレート構文を使用すると失敗します。これは、パブリック用のHTMLを作成する場合に重要です。連結の使用は、特に式が多い場合や長い場合、または括弧を使用して数値と文字列の両方の項目(+演算子を使用)を処理する必要がある場合は、面倒で読みにくいものです。

PHPは、非常にコンパクトな表記法を使用して、変数および一部の式を含む引用文字列を拡張します。 $a="the color is $color";

JavaScriptでは、var a=S('the color is ',color);可変数の引数を使用して、これをサポートする効率的な関数を作成できます。この例では連結に勝る利点はありませんが、式が長くなると、この構文はより明確になる場合があります。または、ドル記号を使用して、PHPのようにJavaScript関数を使用して式の開始を示すことができます。

一方、古いブラウザにテンプレートのような文字列の拡張を提供する効率的な回避策関数を書くことは難しくありません。おそらく誰かがすでにそれを行っているでしょう。

最後に、sprintfは(C、C ++、PHPのように)JavaScriptで記述できると思いますが、他のソリューションよりも少し効率が悪くなります。


0

カスタムの柔軟な補間:

var sourceElm = document.querySelector('input')

// interpolation callback
const onInterpolate = s => `<mark>${s}</mark>`

// listen to "input" event
sourceElm.addEventListener('input', parseInput) 

// parse on window load
parseInput() 

// input element parser
function parseInput(){
  var html = interpolate(sourceElm.value, undefined, onInterpolate)
  sourceElm.nextElementSibling.innerHTML = html;
}

// the actual interpolation 
function interpolate(str, interpolator = ["{{", "}}"], cb){
  // split by "start" pattern
  return str.split(interpolator[0]).map((s1, i) => {
    // first item can be safely ignored
	  if( i == 0 ) return s1;
    // for each splited part, split again by "end" pattern 
    const s2 = s1.split(interpolator[1]);

    // is there's no "closing" match to this part, rebuild it
    if( s1 == s2[0]) return interpolator[0] + s2[0]
    // if this split's result as multiple items' array, it means the first item is between the patterns
    if( s2.length > 1 ){
        s2[0] = s2[0] 
          ? cb(s2[0]) // replace the array item with whatever
          : interpolator.join('') // nothing was between the interpolation pattern
    }

    return s2.join('') // merge splited array (part2)
  }).join('') // merge everything 
}
input{ 
  padding:5px; 
  width: 100%; 
  box-sizing: border-box;
  margin-bottom: 20px;
}

*{
  font: 14px Arial;
  padding:5px;
}
<input value="Everything between {{}} is {{processed}}" />
<div></div>


0

テンプレートはおそらく説明するケースに最適ですが、データや引数を反復可能/配列形式で持っている、または必要とする場合は、を使用できますString.raw

String.raw({
  raw: ["I'm ", " years old!"]
}, 3);

データを配列として使用すると、spread演算子を使用できます。

const args = [3, 'yesterday'];
String.raw({
  raw: ["I'm ", " years old as of ", ""]
}, ...args);

0

探していたものが見つからず、見つかりました-

Node.jsを使用している場合、次のutilように機能するformat関数を備えた組み込みパッケージがあります。

util.format("Hello my name is %s", "Brent");
> Hello my name is Brent

偶然にも、これはconsole.logNode.jsでもフレーバーに組み込まれています-

console.log("This really bad error happened: %s", "ReferenceError");
> This really bad error happened: ReferenceError
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.