ES6テンプレートリテラルと連結文字列


86

Ecma-Script-6の次のコードがあります template literals

let person = {name: 'John Smith'};   
let tpl = `My name is ${person.name}.`;    
let MyVar="My name is "+ person.name+".";

console.log("template literal= "+tpl);  
console.log("my variable = "+MyVar);

出力は次のとおりです。

template literal= My name is John Smith.
my variable = My name is John Smith.

これはフィドルです。正確な違いを検索しようとしましたが、見つかりませんでした。私の質問は、これら2つのステートメントの違いは何ですか。

  let tpl = `My name is ${person.name}.`;    

そして

  let MyVar = "My name is "+ person.name+".";

私はすでにここで文字列をMyVar連結することができperson.nameます、それでテンプレートリテラルを使用するシナリオは何でしょうか?


8
これは、他の言語では一般的な機能です。見た目はすっきりしていて、マルチラインです。
elclanrs 2014

5
「違い」とはどういう意味かわかりませんかtpl === MyVar?唯一の違いは、それらが作成された構文です。文字列の連結とは対照的に、テンプレートは自動エスケープなどに使用できるタグ関数も提供することに注意してください。
ベルギ2014

基本的に、文字列補間と文字列連結の違いは何ですか。
ダムジャンパブリカ2016

速度の違いは考慮する価値がありません。ナノ秒がボトルネックである場合は、別のサーバーなど、他のより大きな問題に対処する必要があります。主観的には、バックティックが他の場所で使用されているアポストロフィに似すぎているため、連結を好みます。
ジェームズ

回答:


108

`Hello ${person.name}`質問の例のように、プレースホルダー(例)のみでテンプレートリテラルを使用している場合、結果は文字列を連結するだけの場合と同じになります。特に複数行の文字列または両方'を含む文字列の場合"、これらの文字をエスケープする必要がないため、主観的に見栄えが良く、読みやすくなります。

読みやすさは素晴らしい機能ですが、テンプレートで最も興味深いのはタグ付きテンプレートリテラルです。

let person = {name: 'John Smith'}; 
let tag = (strArr, name) => strArr[0] + name.toUpperCase() + strArr[1];  
tag `My name is ${person.name}!` // Output: My name is JOHN SMITH!

この例の3行目では、という名前の関数tagが呼び出されています。テンプレート文字列の内容は複数の変数に分割され、tag関数の引数でアクセスできます。リテラルセクション(この例でstrArr[0]My name is 、isの値とstrArr[1]isの値!)と置換(John Smith)です。テンプレートリテラルは、tag関数が返すものに応じて評価されます。

ECMAScriptのwikiのリストに自動的にエスケープまたは入力、またはローカライズをコードするようないくつかの可能なユースケース、。のmsgような文字通りの部分を検索し、My name is それらを現在のロケールの言語、たとえばドイツ語への翻訳に置き換えるという名前のタグ関数を作成できます。

console.log(msg`My name is ${person.name}.`) // Output: Mein Name ist John Smith.

タグ関数によって返される値は、文字列である必要はありません。$次の例のように、文字列を評価し、それをクエリセレクターとして使用してDOMノードのコレクションを返すという名前のタグ関数を作成できます。

$`a.${className}[href=~'//${domain}/']`

2
いいね!$ {person.message}のような別のテンプレートリテラルがそこにある場合、それは一緒に翻訳されますか?
リゴッティ2014

1
@Rigottiそれはmsg関数の実装次第です。確かに、置換値を変換することもできます。
kapex 2014

@ Beatecmascript.orgサイト全体がダウンしているようです。とにかく彼らは彼らのウィキを放棄する計画を持っていたと思うので、私はアーカイブされたバージョンでリンクを更新しました。
kapex 2017

Chromea.${className}[href=~'//${domain}/']コンソールで$を実行しようとしました(前に設定className=''しましたdomain=''が、DOMノードではなく文字列の配列を取得しました:/(他のhadnでは、jsfiddleでコンソールでエラーが発生します:jsfiddle.net/d1fkta76 "Uncaught ReferenceError :$「が定義されていません-なぜ?
カミルKiełczewski

2
ここ@AniketSuryavanshiは、連結性能対テンプレート文字列の比較です:stackoverflow.com/a/29083467/897024数年テンプレート列前に遅くなりましたが、彼らは少し速くなりまし連結比べているように見えます。
kapex

17

ES6`区切り文字としてバックティックを使用して、新しいタイプの文字列リテラルを考え出します。これらのリテラルを使用すると、基本的な文字列補間式を埋め込むことができ、自動的に解析および評価されます。

let actor = {name: 'RajiniKanth', age: 68};

let oldWayStr = "<p>My name is " + actor.name + ",</p>\n" +
  "<p>I am " + actor.age + " old</p>\n";

let newWayHtmlStr =
 `<p>My name is ${actor.name},</p>
  <p>I am ${actor.age} old</p>`;

console.log(oldWayStr);
console.log(newWayHtmlStr);

ご覧のとおり、文字列リテラルとして解釈される一連の文字の周りに..``を使用しましたが、フォームの式はすべて、${..}すぐにインラインで解析および評価されます。

補間された文字列リテラルの非常に優れた利点の1つは、複数の行に分割できることです。

var Actor = {"name" : "RajiniKanth"};

var text =
`Now is the time for all good men like ${Actor.name}
to come to the aid of their
country!`;
console.log( text );
// Now is the time for all good men
// to come to the aid of their
// country!

補間された式

関数呼び出し、インライン関数式呼び出し、さらにはその他の有効な式${..}を、補間された文字列内にlit‐ eral含めることができますinterpo‐ lated string literals

function upper(s) {
 return s.toUpperCase();
}
var who = "reader"
var text =
`A very ${upper( "warm" )} welcome
to all of you ${upper( `${who}s` )}!`;
console.log( text );
// A very WARM welcome
// to all of you READERS!

ここで、内部の$ {who} s``補間文字列リテラルは、"s"who + "s"とは対照的に、who変数を文字列と組み合わせるときに少し便利でした。また、単なる補間文字列リテラルがあるノートを保つためにlexically scopedはない、それが表示される場所dynamically scopedどのような方法で

function foo(str) {
 var name = "foo";
 console.log( str );
}
function bar() {
 var name = "bar";
 foo( `Hello from ${name}!` );
}
var name = "global";
bar(); // "Hello from bar!"

template literalHTMLにforを使用すると、煩わしさが軽減されるため、間違いなく読みやすくなります。

昔ながらの方法:

'<div class="' + className + '">' +
  '<p>' + content + '</p>' +
  '<a href="' + link + '">Let\'s go</a>'
'</div>';

ES6

`<div class="${className}">
  <p>${content}</p>
  <a href="${link}">Let's go</a>
</div>`
  • 文字列は複数行にまたがることができます。
  • 引用符をエスケープする必要はありません。
  • 次のようなグループ化は避けることができます: '">'
  • plus演算子を使用する必要はありません。

タグ付きテンプレートリテラル

template文字列にタグを付けることもできtemplateます。文字列にタグを付けると、literalsおよび置換が関数に渡され、結果の値が返されます。

function myTaggedLiteral(strings) {
  console.log(strings);
}

myTaggedLiteral`test`; //["test"]

function myTaggedLiteral(strings,value,value2) {
  console.log(strings,value, value2);
}
let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// "Neat"
// 5

spreadここで演算子を使用して、複数の値を渡すことができます。最初の引数(文字列と呼びます)は、すべてのプレーン文字列(補間された式の間のもの)の配列です。

次に、以降のすべての引数を、を使用してvaluesという配列にまとめ... gather/rest operatorますが、もちろん、上記のように文字列パラメーターに続く個別の名前付きパラメーターとして残すこともできます(value1, value2 etc)

function myTaggedLiteral(strings,...values) {
  console.log(strings);
  console.log(values);    
}

let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// ["Neat", 5]

argument(s)私たちの価値観に集め、配列は、文字列リテラルで見つかった、既に評価された補間式の結果です。Atagged string literalは、補間が評価された後、最終的な文字列値がコンパイルされる前の処理ステップのようなものであり、リテラルからの文字列の生成をより細かく制御できます。を作成する例を見てみましょうre-usable templates

const Actor = {
  name: "RajiniKanth",
  store: "Landmark"
}

const ActorTemplate = templater`<article>
  <h3>${'name'} is a Actor</h3>
  <p>You can find his movies at ${'store'}.</p>

</article>`;

function templater(strings, ...keys) {
  return function(data) {
  let temp = strings.slice();
  keys.forEach((key, i) => {
  temp[i] = temp[i] + data[key];
  });
  return temp.join('');
  }
};

const myTemplate = ActorTemplate(Actor);
console.log(myTemplate);

生の文字列

タグ関数stringsは、と呼ばれる最初の引数を受け取りarrayます。これはです。ただし、追加のデータが含まれています。すべての文字列の未処理の未処理バージョンです。次の.rawように、プロパティを使用してこれらの生の文字列値にアクセスできます。

function showraw(strings, ...values) {
 console.log( strings );
 console.log( strings.raw );
}
showraw`Hello\nWorld`;

ご覧のとおりraw、文字列のバージョンはエスケープされた\ nシーケンスを保持しますが、処理されたバージョンの文字列はそれをエスケープされていない実際の改行のように扱います。 ES6文字列リテラルタグとして使用できる組み込み関数が付属しています String.raw(..)strings:の生バージョンを通過するだけです。

console.log( `Hello\nWorld` );
/* "Hello
World" */

console.log( String.raw`Hello\nWorld` );
// "Hello\nWorld"

4

それはずっときれいで、コメントで述べられているように、他の言語の一般的な機能です。私が気に入ったもう1つの点は、文字列を書くときに非常に役立つ改行です。

let person = {name: 'John Smith', age: 24, greeting: 'Cool!' };

let usualHtmlStr = "<p>My name is " + person.name + ",</p>\n" +
                   "<p>I am " + person.age + " old</p>\n" +
                   "<strong>\"" + person.greeting +"\" is what I usually say</strong>";


let newHtmlStr = 
 `<p>My name is ${person.name},</p>
  <p>I am ${person.age} old</p>
  <p>"${person.greeting}" is what I usually say</strong>`;


console.log(usualHtmlStr);
console.log(newHtmlStr);

文字列とリテラルに改行があることに大きな違いがあるかどうかはわかりません。このes6fiddle.net/i3vj1ldlを確認してください。リテラルは改行の代わりにスペースを置くだけです
Naeem Shaikh 2014

1
うわー、それが大きな違いだとは言わなかった。リテラルの改行は単なるシンタックスシュガーです。読みやすさのためだけです。
リゴッティ2014

しかし、それでもあなたは良い違いを指摘しました。しかし、あなたの答えを受け入れる前に、私は大きな違いを示すより良い答えをもう少し待ちます(もしあれば!):)
Naeem Shaikh 2014

2
@NaeemShaikh大変申し訳ありませんが、リテラルの改行は実際には機能します。ES6Fiddleがそれをテストするためのひどい方法であることに気づきました。答えを編集します。
リゴッティ2014

2

一方で、私の答えは直接質問に対処していません。配列結合を優先してテンプレートリテラルを使用することの1つの欠点を指摘することは興味深いかもしれないと思いました。

私が持っているとしましょう

let patient1 = {firstName: "John", lastName: "Smith"};
let patient2 = {firstName: "Dwayne", lastName: "Johnson", middleName: "'The Rock'"};

したがって、middleNameを持っている患者と持っていない患者がいます。

患者のフルネームを表す文字列が必要な場合

let patientName = `${patient1.firstName} ${patient1.middleName} ${patient1.lastName}`;

そうすると、これは「ジョン未定義のスミス」になります

しかし、私がやった場合

let patientName = [patient1.firstName, patient1.middleName,  patient1.lastName].join(" ");

そうすると、これはただの「ジョン・スミス」になります

編集

General_Twyckenhamは、「」で結合すると、「John」と「Smith」の間に余分なスペースが生じると指摘しました。

これを回避するために、結合の前にフィルターを使用して、偽の値を取り除くことができます。 [patient1.firstName, patient1.middleName, patient1.lastName].filter(el => el).join(" ");


2
実際、それは完全には正しくありません。このjoinバージョンでは、ジョン・スミスに余分なスペースが与えられます。ご想像のとおり、これは望ましくないことがよくあります。このため修正は使用することですmap。そうのように[patient1.firstName, patient1.middleName, patient1.lastName].map(el => el).join(" ");
General_Twyckenham

@General_Twyckenhamああ、私はあなたの主張を理解しています。良いキャッチ。また、余分なスペースを取り除くために、マップではなくフィルターにする必要があります。答えを編集します、ありがとう。
Dhruv Prakash 2018年

おっと-ええ、filter私が意図した機能でした。
General_Twyckenham

そして、この議論によれば、文字列の連結は配列の結合よりも高速です。stackoverflow.com/questions/7299010/...
マイケル・ハーレー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.