8. テンプレートリテラル
目次
本書をサポートしてください:購入 (PDF, EPUB, MOBI) または 寄付
(広告、ブロックしないでください。)

8. テンプレートリテラル



8.1 概要

ES6には、テンプレートリテラルタグ付きテンプレートリテラルという2種類の新しいリテラルがあります。これら2つのリテラルは名前と見た目が似ていますが、かなり異なります。そのため、区別することが重要です。

テンプレートリテラルは、複数行にまたがり、インターポーレートされた式(${···}を使用して挿入)を含むことができる文字列リテラルです。

const firstName = 'Jane';
console.log(`Hello ${firstName}!
How are you
today?`);

// Output:
// Hello Jane!
// How are you
// today?

タグ付きテンプレートリテラル(略してタグ付きテンプレート)は、テンプレートリテラルの前に関数を記述することで作成されます。

> String.raw`A \tagged\ template`
'A \\tagged\\ template'

タグ付きテンプレートは関数呼び出しです。前の例では、String.rawメソッドが呼び出されて、タグ付きテンプレートの結果が生成されています。

8.2 はじめに

リテラルは、値を生成する構文上の構成要素です。文字列リテラル(文字列を生成する)や正規表現リテラル(正規表現オブジェクトを生成する)などが例として挙げられます。ECMAScript 6には、2つの新しいリテラルがあります。

テンプレートリテラルとタグ付きテンプレートの名前はやや誤解を招きやすいことに注意することが重要です。Web開発でよく使用されるテンプレート(例:JSONデータで埋め込むことができる空欄のあるテキストファイル)とは関係ありません。

8.2.1 テンプレートリテラル

テンプレートリテラルは、複数行にまたがり、式をインターポーレート(その結果を含める)できる新しい種類の文字列リテラルです。例えば

const firstName = 'Jane';
console.log(`Hello ${firstName}!
How are you
today?`);

// Output:
// Hello Jane!
// How are you
// today?

リテラル自体はバッククォート(`)で区切られ、リテラル内のインターポーレートされた式は${}で区切られます。テンプレートリテラルは常に文字列を生成します。

8.2.2 テンプレートリテラルでのエスケープ

バックスラッシュはテンプレートリテラル内でのエスケープに使用されます。

これにより、テンプレートリテラル内でバッククォートと${を記述できます。

> `\``
'`'
> `$` // OK
'$'
> `${`
SyntaxError
> `\${`
'${'
> `\${}`
'${}'

それ以外は、バックスラッシュは文字列リテラルと同様に機能します。

> `\\`
'\\'
> `\n`
'\n'
> `\u{58}`
'X'

8.2.3 テンプレートリテラルにおける改行文字は常にLF (\n)

改行を終了する一般的な方法は次のとおりです。

これらの改行文字はすべて、テンプレートリテラルでLFに正規化されます。つまり、次のコードはすべてのプラットフォームでtrueを出力します。

const str = `BEFORE
AFTER`;
console.log(str === 'BEFORE\nAFTER'); // true

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

以下はタグ付きテンプレートリテラル(略してタグ付きテンプレート)です。

tagFunction`Hello ${firstName} ${lastName}!`

式の後にテンプレートリテラルを配置すると、パラメータリスト(括弧内のコンマ区切りの値)が関数呼び出しをトリガーする方法と同様に、関数呼び出しがトリガーされます。(実際には、最初のパラメータは単なる配列以上のものですが、それは後で説明します)。

tagFunction(['Hello ', ' ', '!'], firstName, lastName)

したがって、バッククォート内のコンテンツの前にある名前は、呼び出す関数の名前であるタグ関数です。タグ関数は、2種類の異なるデータを受け取ります。

テンプレート文字列は静的に(コンパイル時に)知られていますが、置換は実行時にのみ知られています。タグ関数は、そのパラメータを自由に処理できます。テンプレート文字列を完全に無視したり、任意の種類の値を返したりすることができます。

さらに、タグ関数は各テンプレート文字列の2つのバージョンを取得します。

これにより、String.raw(後で説明します)が機能します。

> String.raw`\n` === '\\n'
true

8.3 タグ付きテンプレートリテラルの使用例

タグ付きテンプレートリテラルを使用すると、JavaScriptがほとんどのパース処理を行うため、カスタムの埋め込みサブ言語(ドメイン固有言語と呼ばれることもあります)を簡単に実装できます。結果を受け取る関数を作成するだけで済みます。

例を見てみましょう。その一部は、テンプレートリテラルの元の提案(それらを古い名前である準リテラルで参照しています)に触発されています。

8.3.1 ロー文字列

ES6には、バックスラッシュに特別な意味がないロー文字列用のタグ関数String.rawが含まれています。

const str = String.raw`This is a text
with multiple lines.
Escapes are not interpreted,
\n is not a newline.`;

これは、バックスラッシュを含む文字列を作成する必要がある場合に便利です。例えば

function createNumberRegExp(english) {
    const PERIOD = english ? String.raw`\.` : ','; // (A)
    return new RegExp(`[0-9]+(${PERIOD}[0-9]+)?`);
}

行Aでは、String.rawを使用することで、正規表現リテラルのようにバックスラッシュを書くことができます。通常の文字列リテラルでは、2回エスケープする必要があります。まず、正規表現のドットをエスケープする必要があります。次に、文字列リテラルのバックスラッシュをエスケープする必要があります。

8.3.2 シェルコマンド

const proc = sh`ps ax | grep ${pid}`;

(出典:David Herman)

8.3.3 バイト文字列

const buffer = bytes`455336465457210a`;

(出典:David Herman)

8.3.4 HTTPリクエスト

POST`http://foo.org/bar?a=${a}&b=${b}
     Content-Type: application/json
     X-Credentials: ${credentials}

     { "foo": ${foo},
       "bar": ${bar}}
     `
     (myOnReadyStateChangeHandler);

(出典:Luke Hoban)

8.3.5 より強力な正規表現

Steven Levithanは、を挙げて、タグ付きテンプレートリテラルを彼の正規表現ライブラリXRegExpで使用する方法を示しています。

タグ付きテンプレートを使用しない場合、次のコードのように記述します。

var parts = '/2015/10/Page.html'.match(XRegExp(
  '^ # match at start of string only \n' +
  '/ (?<year> [^/]+ ) # capture top dir name as year \n' +
  '/ (?<month> [^/]+ ) # capture subdir name as month \n' +
  '/ (?<title> [^/]+ ) # capture base name as title \n' +
  '\\.html? $ # .htm or .html file ext at end of path ', 'x'
));

console.log(parts.year); // 2015

XRegExpにより、名前付きグループ(yearmonthtitle)とxフラグが得られることがわかります。このフラグを使用すると、ほとんどの空白は無視され、コメントを挿入できます。

文字列リテラルがここでうまく機能しない理由は2つあります。まず、文字列リテラルに対してエスケープするために、すべての正規表現のバックスラッシュを2回入力する必要があります。次に、複数行を入力することが面倒です。

文字列を追加する代わりに、現在の行をバックスラッシュで終了すると、次の行で文字列リテラルを続けることもできます。しかし、それでも、特に各行の最後に\nによる明示的な改行が必要なため、視覚的な混乱が多くあります。

var parts = '/2015/10/Page.html'.match(XRegExp(
  '^ # match at start of string only \n\
  / (?<year> [^/]+ ) # capture top dir name as year \n\
  / (?<month> [^/]+ ) # capture subdir name as month \n\
  / (?<title> [^/]+ ) # capture base name as title \n\
  \\.html? $ # .htm or .html file ext at end of path ', 'x'
));

バックスラッシュと複数行の問題は、タグ付きテンプレートで解消されます。

var parts = '/2015/10/Page.html'.match(XRegExp.rx`
    ^ # match at start of string only
    / (?<year> [^/]+ ) # capture top dir name as year
    / (?<month> [^/]+ ) # capture subdir name as month
    / (?<title> [^/]+ ) # capture base name as title
    \.html? $ # .htm or .html file ext at end of path
`);

さらに、タグ付きテンプレートでは、${v}を使用して値vを挿入できます。正規表現ライブラリは、文字列をエスケープし、正規表現をそのまま挿入するものと予想します。例えば

var str   = 'really?';
var regex = XRegExp.rx`(${str})*`;

これは、次のものと同等です。

var regex = XRegExp.rx`(really\?)*`;

8.3.6 クエリ言語

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

これは、CSSクラスがclassNameで、ターゲットが指定されたドメインを持つURLであるすべての<a>タグを検索するDOMクエリです。タグ関数$は、引数が正しくエスケープされるようにするため、手動での文字列連結よりも安全なアプローチになります。

8.3.7 タグ付きテンプレートによるReact JSX

Facebook Reactは、「ユーザーインターフェースを構築するためのJavaScriptライブラリ」です。ユーザーインターフェースの仮想DOMツリーを構築できるようにするオプションの言語拡張JSXがあります。この拡張機能により、コードが簡潔になりますが、非標準であり、JavaScriptエコシステムの残りの部分との互換性が損なわれます。

ライブラリt7.jsはJSXの代替手段を提供し、t7でタグ付けされたテンプレートを使用します。

t7.module(function(t7) {
  function MyWidget(props) {
    return t7`
      <div>
        <span>I'm a widget ${ props.welcome }</span>
      </div>
    `;
  }

  t7.assign('Widget', MyWidget);

  t7`
    <div>
      <header>
        <Widget welcome="Hello world" />
      </header>
    </div>
  `;
});

テンプレートリテラルを使用しない理由」において、Reactチームはなぜテンプレートリテラルを使用しない選択をしたのかを説明しています。課題の1つは、タグ付きテンプレート内でコンポーネントにアクセスすることです。例えば、前の例の2番目のタグ付きテンプレートではMyWidgetにアクセスします。冗長な方法としては、以下のように行うことができます。

<${MyWidget} welcome="Hello world" />

代わりに、t7.jsはt7.assign()を介して埋められるレジストリを使用します。これは追加の設定が必要になりますが、テンプレートリテラルはより見栄えが良くなります。特に、開始タグと終了タグの両方がある場合です。

8.3.8 Facebook GraphQL

Facebook Relayは、「データ駆動型のReactアプリケーションを構築するためのJavaScriptフレームワーク」です。その一部として、クエリ言語GraphQLがあり、そのクエリはRelay.QLでタグ付けされたテンプレートを介して作成できます。例(Relayのホームページから借用

class Tea extends React.Component {
  render() {
    var {name, steepingTime} = this.props.tea;
    return (
      <li key={name}>
        {name} (<em>{steepingTime} min</em>)
      </li>
    );
  }
}
Tea = Relay.createContainer(Tea, {
  fragments: { // (A)
    tea: () => Relay.QL`
      fragment on Tea {
        name,
        steepingTime,
      }
    `,
  },
});

class TeaStore extends React.Component {
  render() {
    return <ul>
      {this.props.store.teas.map(
        tea => <Tea tea={tea} />
      )}
    </ul>;
  }
}
TeaStore = Relay.createContainer(TeaStore, {
  fragments: { // (B)
    store: () => Relay.QL`
      fragment on Store {
        teas { ${Tea.getFragment('tea')} },
      }
    `,
  },
});

A行とB行から始まるオブジェクトはフラグメントを定義しており、クエリを返すコールバックを介して定義されます。フラグメントteaの結果はthis.props.teaに入れられます。フラグメントstoreの結果はthis.props.storeに入れられます。

これがクエリが操作するデータです。

const STORE = {
  teas: [
    {name: 'Earl Grey Blue Star', steepingTime: 5},
    ···
  ],
};

このデータはGraphQLSchemaのインスタンスにラップされ、そこでfragment on Storeで言及されているようにStoreという名前が付けられます。

8.3.9 テキストローカリゼーション(L10N)

このセクションでは、異なる言語と異なるロケール(数値、時刻などのフォーマット方法)をサポートする、テキストローカリゼーションの簡単なアプローチについて説明します。次のメッセージがあるとします。

alert(msg`Welcome to ${siteName}, you are visitor
          number ${visitorNumber}:d!`);

タグ関数msgは次のように機能します。

まず、リテラルの部分を連結して、テーブルで翻訳を検索するために使用できる文字列を作成します。前の例の検索文字列は次のとおりです。

'Welcome to {0}, you are visitor number {1}!'

この検索文字列は、例えば、ドイツ語の翻訳にマッピングできます。

'Besucher Nr. {1}, willkommen bei {0}!'

英語の「翻訳」は、検索文字列と同じになります。

次に、検索の結果を使用して置換を表示します。検索結果にはインデックスが含まれているため、置換の順序を並べ替えることができます。これはドイツ語で行われており、訪問者数はサイト名の前に来ます。置換のフォーマット方法は、:dなどのアノテーションで影響を受ける可能性があります。このアノテーションは、visitorNumberにはロケール固有の小数点セパレータを使用する必要があることを意味します。したがって、考えられる英語の結果は次のとおりです。

Welcome to ACME Corp., you are visitor number 1,300!

ドイツ語では、次のような結果になります。

Besucher Nr. 1.300, willkommen bei ACME Corp.!

8.3.10 タグなしテンプレートリテラルによるテキストテンプレート化

次のデータをテーブルに表示するHTMLを作成したいとしましょう。

const data = [
    { first: '<Jane>', last: 'Bond' },
    { first: 'Lars', last: '<Croft>' },
];

前述のように、テンプレートリテラルはテンプレートではありません。

テンプレートは基本的に関数です。入力はデータ、出力はテキストです。そして、その説明は、テンプレートリテラルを実際のテンプレートに変換する方法の手がかりを与えてくれます。配列addrsを文字列にマッピングする関数としてテンプレートtmplを実装してみましょう。

const tmpl = addrs => `
    <table>
    ${addrs.map(addr => `
        <tr><td>${addr.first}</td></tr>
        <tr><td>${addr.last}</td></tr>
    `).join('')}
    </table>
`;
console.log(tmpl(data));
// Output:
// <table>
//
//     <tr><td><Jane></td></tr>
//     <tr><td>Bond</td></tr>
//
//     <tr><td>Lars</td></tr>
//     <tr><td><Croft></td></tr>
//
// </table>

外側のテンプレートリテラルは、ブラケット<table></table>を提供します。内部では、文字列の配列を結合することによって文字列を生成するJavaScriptコードを埋め込んでいます。配列は、各アドレスを2つのテーブル行にマッピングすることによって作成されます。プレーンテキストの部分<Jane><Croft>は適切にエスケープされていません。タグ付きテンプレートを介してそれを行う方法は、次のセクションで説明します。

8.3.10.1 本番コードでこのテクニックを使用する必要がありますか?

これは、小規模なテンプレート化タスクのための便利な迅速なソリューションです。大規模なタスクの場合は、Handlebars.jsなどのより強力なソリューションや、Reactで使用されているJSX構文を使用することを検討してください。

謝辞:このテキストテンプレート化へのアプローチは、Claus Reinkeによるアイデアに基づいています。

8.3.11 HTMLテンプレート化のためのタグ関数

前のセクションで行ったように、HTMLテンプレート化にタグなしテンプレートを使用する場合と比較して、タグ付きテンプレートには2つの利点があります。

テンプレートのコードは次のようになります。タグ関数の名前はhtmlです。

const tmpl = addrs => html`
    <table>
    ${addrs.map(addr => html`
        <tr><td>!${addr.first}</td></tr>
        <tr><td>!${addr.last}</td></tr>
    `)}
    </table>
`;
const data = [
    { first: '<Jane>', last: 'Bond' },
    { first: 'Lars', last: '<Croft>' },
];
console.log(tmpl(data));
// Output:
// <table>
//
//     <tr><td>&lt;Jane&gt;</td></tr>
//     <tr><td>Bond</td></tr>
//
//     <tr><td>Lars</td></tr>
//     <tr><td>&lt;Croft&gt;</td></tr>
//
// </table>

JaneCroftの周りの山かっこはエスケープされていますが、trtdの周りの山かっこはエスケープされていません。

置換の前に感嘆符(!${addr.first})を付けると、HTMLエスケープされます。タグ関数は、置換の前にあるテキストをチェックして、エスケープするかどうかを判断します。

htmlの実装は後で示します

8.4 タグ関数の実装

以下は、タグ付きテンプレートリテラルです。

tagFunction`lit1\n${subst1} lit2 ${subst2}`

このリテラルは、(おおよそ)次の関数呼び出しをトリガーします。

tagFunction(['lit1\n',  ' lit2 ', ''], subst1, subst2)

正確な関数呼び出しは、次のようになります。

// Globally: add template object to per-realm template map
{
    // “Cooked” template strings: backslash is interpreted
    const templateObject = ['lit1\n',  ' lit2 ', ''];
    // “Raw” template strings: backslash is verbatim
    templateObject.raw   = ['lit1\\n', ' lit2 ', ''];

    // The Arrays with template strings are frozen
    Object.freeze(templateObject.raw);
    Object.freeze(templateObject);

    __templateMap__[716] = templateObject;
}

// In-place: invocation of tag function
tagFunction(__templateMap__[716], subst1, subst2)

タグ関数が受信する入力には2種類あります。

  1. テンプレート文字列(最初の引数):変更されないタグ付きテンプレートの静的な部分(例:' lit2 ')。テンプレートオブジェクトはテンプレート文字列の2つのバージョンを格納します。
    • 調理済み:\nなどのエスケープが解釈されたもの。templateObject[0]などに格納されます。
    • 未加工:解釈されていないエスケープを含むもの。templateObject.raw[0]などに格納されます。
  2. 置換(残りの引数):${}を介してテンプレートリテラルに埋め込まれた値(例:subst1)。置換は動的であり、呼び出しごとに変更できます。

グローバルテンプレートオブジェクトの背後にある考え方は、同じタグ付きテンプレートが複数回実行される可能性がある(例:ループ内または関数内)ことです。テンプレートオブジェクトにより、タグ関数は以前の呼び出しからのデータをキャッシュできます。入力の種類1(テンプレート文字列)から派生したデータをオブジェクトに格納して、再計算を回避できます。キャッシュはレルムごとに実行されます(ブラウザのフレームと考えてください)。つまり、呼び出しサイトとレルムごとに1つのテンプレートオブジェクトがあります。

8.4.1 テンプレート文字列の数と置換の数の比較

次のタグ関数を使用して、テンプレート文字列の数と置換の数を比較してみましょう。

function tagFunc(templateObject, ...substs) {
    return { templateObject, substs };
}

テンプレート文字列の数は、常に置換の数プラス1です。言い換えれば、すべての置換は常に2つのテンプレート文字列で囲まれています。

templateObject.length === substs.length + 1

置換がリテラルの先頭にある場合、空のテンプレート文字列が接頭辞として付けられます。

> tagFunc`${'subst'}xyz`
{ templateObject: [ '', 'xyz' ], substs: [ 'subst' ] }

置換がリテラルの最後にある場合、空のテンプレート文字列が接尾辞として付けられます。

> tagFunc`abc${'subst'}`
{ templateObject: [ 'abc', '' ], substs: [ 'subst' ] }

空のテンプレートリテラルは、1つのテンプレート文字列と置換を生成しません。

> tagFunc``
{ templateObject: [ '' ], substs: [] }

8.4.2 タグ付きテンプレートリテラルのエスケープ:調理済みと未加工

テンプレート文字列は、調理済みと未加工の2つの解釈で使用できます。これらの解釈はエスケープに影響します。

タグ関数describeを使用すると、それが何を意味するのかを調べることができます。

function describe(tmplObj, ...substs) {
    return {
        Cooked: merge(tmplObj, substs),
        Raw: merge(tmplObj.raw, substs),
    };
}
function merge(tmplStrs, substs) {
    // There is always at least one element in tmplStrs
    let result = tmplStrs[0];
    substs.forEach((subst, i) => {
        result += String(subst);
        result += tmplStrs[i+1];
    });
    return result;
}

このタグ関数を使用してみましょう。

> describe`${3+3}`
{ Cooked: '6', Raw: '6' }

> describe`\${3+3}`
{ Cooked: '${3+3}', Raw: '\\${3+3}' }

> describe`\\${3+3}`
{ Cooked: '\\6', Raw: '\\\\6' }

> describe`\``
{ Cooked: '`', Raw: '\\`' }

ご覧のように、調理済み解釈に置換またはバッククォートがある場合は、未加工解釈にもあります。ただし、リテラルからのすべてのバックスラッシュは、未加工解釈に表示されます。

バックスラッシュの他の出現は、次のように解釈されます。

例えば

> describe`\\`
{ Cooked: '\\', Raw: '\\\\' }

> describe`\n`
{ Cooked: '\n', Raw: '\\n' }

> describe`\u{58}`
{ Cooked: 'X', Raw: '\\u{58}' }

要約すると、未加工モードでのバックスラッシュの唯一の効果は、置換とバッククォートをエスケープすることです。

8.4.3 例:String.raw

String.rawの実装方法は次のとおりです。

function raw(strs, ...substs) {
    let result = strs.raw[0];
    for (const [i,subst] of substs.entries()) {
        result += subst;
        result += strs.raw[i+1];
    }
    return result;
}

8.4.4 例:HTMLテンプレート化のためのタグ関数の実装

前に、HTMLテンプレート化のためのタグ関数htmlを示しました。

const tmpl = addrs => html`
    <table>
    ${addrs.map(addr => html`
        <tr><td>!${addr.first}</td></tr>
        <tr><td>!${addr.last}</td></tr>
    `)}
    </table>
`;
const data = [
    { first: '<Jane>', last: 'Bond' },
    { first: 'Lars', last: '<Croft>' },
];
console.log(tmpl(data));
// Output:
// <table>
//
//     <tr><td>&lt;Jane&gt;</td></tr>
//     <tr><td>Bond</td></tr>
//
//     <tr><td>Lars</td></tr>
//     <tr><td>&lt;Croft&gt;</td></tr>
//
// </table>

置換の前に感嘆符(!${addr.first})を付けると、HTMLエスケープされます。タグ関数は、置換の前にあるテキストをチェックして、エスケープするかどうかを判断します。

これはhtmlの実装です。

function html(templateObject, ...substs) {
    // Use raw template strings: we don’t want
    // backslashes (\n etc.) to be interpreted
    const raw = templateObject.raw;

    let result = '';

    substs.forEach((subst, i) => {
        // Retrieve the template string preceding
        // the current substitution
        let lit = raw[i];

        // In the example, map() returns an Array:
        // If `subst` is an Array (and not a string),
        // we turn it into a string
        if (Array.isArray(subst)) {
            subst = subst.join('');
        }

        // If the substitution is preceded by an exclamation
        // mark, we escape special characters in it
        if (lit.endsWith('!')) {
            subst = htmlEscape(subst);
            lit = lit.slice(0, -1);
        }
        result += lit;
        result += subst;
    });
    // Take care of last template string
    result += raw[raw.length-1]; // (A)

    return result;
}

置換よりも常に1つ多いテンプレート文字列があるため、A行で最後のテンプレート文字列を追加する必要があります。

以下は、htmlEscape()の簡単な実装です。

function htmlEscape(str) {
    return str.replace(/&/g, '&amp;') // first!
              .replace(/>/g, '&gt;')
              .replace(/</g, '&lt;')
              .replace(/"/g, '&quot;')
              .replace(/'/g, '&#39;')
              .replace(/`/g, '&#96;');
}
8.4.4.1 その他のアイデア

このテンプレート化アプローチでは、他にもできることがあります。

8.4.5 例:正規表現の組み立て

正規表現インスタンスを作成するには、2つの方法があります。

後者を使用する場合は、必要なすべての要素が利用可能になるまで実行時まで待つ必要があるためです。3種類の要素を連結して正規表現を作成しています。

  1. 静的なテキスト
  2. 動的な正規表現
  3. 動的なテキスト

#3の場合、特殊文字(ドット、角括弧など)をエスケープする必要がありますが、#1と#2はそのまま使用できます。正規表現タグ関数regexがこのタスクに役立ちます。

const INTEGER = /\d+/;
const decimalPoint = '.'; // locale-specific! E.g. ',' in Germany
const NUMBER = regex`${INTEGER}(${decimalPoint}${INTEGER})?`;

regexは次のようになります。

function regex(tmplObj, ...substs) {
    // Static text: verbatim
    let regexText = tmplObj.raw[0];
    for ([i, subst] of substs.entries()) {
        if (subst instanceof RegExp) {
            // Dynamic regular expressions: verbatim
            regexText += String(subst);
        } else {
            // Other dynamic data: escaped
            regexText += quoteText(String(subst));
        }
        // Static text: verbatim
        regexText += tmplObj.raw[i+1];
    }
    return new RegExp(regexText);
}
function quoteText(text) {
    return text.replace(/[\\^$.*+?()[\]{}|=!<>:-]/g, '\\$&');
}

8.5 FAQ:テンプレートリテラルとタグ付きテンプレートリテラル

8.5.1 テンプレートリテラルとタグ付きテンプレートリテラルはどこから来たのですか?

テンプレートリテラルとタグ付きテンプレートリテラルは、E言語から借用されたもので、この機能を準リテラルと呼んでいます。

8.5.2 マクロとタグ付きテンプレートリテラルの違いは何ですか?

マクロを使用すると、カスタム構文を持つ言語構成要素を実装できます。JavaScriptのように構文が複雑なプログラミング言語のマクロを提供することは困難です。この分野の研究は現在進行中です(Mozillaのsweet.jsを参照)。

マクロは、タグ付きテンプレートよりもサブ言語の実装にはるかに強力ですが、言語のトークン化に依存します。したがって、タグ付きテンプレートはテキストコンテンツを専門とするため、補完的なものです。

8.5.3 外部ソースからテンプレートリテラルを読み込むことはできますか?

`Hello ${name}!`のようなテンプレートリテラルを外部ソース(例:ファイル)から読み込む場合はどうすればよいですか?

そのようなことをすると、テンプレートリテラルを誤用しています。テンプレートリテラルには任意の式を含めることができ、リテラルであるため、他の場所から読み込むことは、式または文字列リテラルを読み込むことと同様であり、eval()または同様の方法を使用する必要があります。

8.5.4 なぜバックティックがテンプレートリテラルの区切り文字になっているのですか?

バックティックは、JavaScriptでまだ使用されていなかった少数のASCII文字の1つでした。補間のための構文${}は非常に一般的です(Unixシェルなど)。

8.5.5 テンプレートリテラルはかつてテンプレート文字列と呼ばれていませんでしたか?

テンプレートリテラルという用語は、ES6仕様の作成中に比較的遅く変更されました。古い用語を次に示します。

次へ:9. 変数とスコープ