Skip to content

Instantly share code, notes, and snippets.

@kuu

kuu/TemplateStrings.md

Last active Jan 30, 2016
Embed
What would you like to do?

Japanese translation from the original post in English.

原文: [Getting Literal With ES6 Template Strings by Addy Osmani] (http://updates.html5rocks.com/2015/01/ES6-Template-Strings)

#ES6のテンプレート文字列

従来のJavaScriptの文字列処理はPythonやRubyに比べて非力でしたが、ES6のテンプレート文字列はこの状況を根本的に覆します。(テンプレート文字列はChrome 41からサポートされています。)それによりプログラマはドメイン固有言語(domain-specific language、DSL)を定義する事が可能になります。以下はテンプレート文字列が提供する機能です。

  • 文字列の挿入
  • 式を文字列に埋め込む
  • 複数行に渡る文字列を簡単に記述できる
  • 文字列の整形
  • タグ付けによるエスケープ処理、ローカライズ

上記の機能を実現するために、テンプレート文字列の仕様では、既存のJavaScriptの文字列に機能を追加するのではなく、まったく異なるシンタックスが導入されました。

##シンタックス

テンプレート文字列では従来JavaScriptの文字列で使われていたシングルクォートもしくはダブルクォートではなく、バッククォート(`)が使用されます。以下のような記述となります。

    var greeting = `Yo World!`;

このままでは従来の文字列と機能的に何ら変わらないので、以降で変更を加えていきます。

##文字列置換

まず、テンプレート文字列の一番分かりやすい使い方は文字列置換です。文字列置換はテンプレート文字列の中にJavaScriptの式(例:複数の変数を文字列演算子で連結したもの等)を配置することで行います。

以下のようにテンプレート文字列中の${ }で囲われた部分はプレースホルダーとして作用するので、ここに式を記述します。

    // 文字列置換
    var name = "Brendan";
    console.log(`Yo, ${name}!`);

    // => "Yo, Brendan!"

文字列置換のプレースホルダー内では通常のJavaScriptの式が使用できるため、変数名以外にも様々なものを記述することができます。例えば以下のように短い数式をインラインで埋め込むことも可能です。

    var a = 10;
    var b = 10;
    console.log(`JavaScript first appeared ${a+b} years ago. Crazy!`);

    //=> JavaScript first appeared 20 years ago. Crazy!

    console.log(`The number of JS MVC frameworks is ${2 * (a + b)} and not ${10 * (a + b)}.`);
    //=> The number of JS frameworks is 40 and not 2000.

また、以下のように関数呼び出しも行えます。

    function fn() { return "I am a result. Rarr"; }
    console.log(`foo ${fn()} bar`);
    //=> foo I am a result. Rarr bar.

その他にも${}の中にはプロパティのアクセスやメソッド呼び出し等、あらゆるタイプの式が記述できます。

    var user = {name: 'Caitlin Potter'};
    console.log(`Thanks for getting this into V8, ${user.name.toUpperCase()}.`);

    // => "Thanks for getting this into V8, CAITLIN POTTER";

    // その他の例
    var thing = 'drugs';
    console.log(`Say no to ${thing}. Although if you're talking to ${thing} you may already be on ${thing}.`);

    // => Say no to drugs. Although if you're talking to drugs you may already be on drugs.

テンプレート文字列の中でバッククォートの文字を使いたい場合は、以下のようにバックスラッシュ(\)を使ってエスケープします。

    var greeting = `\`Yo\` World!`;

##複数行に渡る文字列

従来、JavaScriptで複数行の文字列を扱おうとするとトリッキーにならざるを得ませんでした。文字列が複数行に渡る場合、改行の前にバックスラッシュ(\)を挿入する必要があります。

    var greeting = "Yo \
    World";

上記のやり方はほとんどのJavaScriptエンジンで動作しますが、若干ハックのようにも感じられます。また、以下のように文字列演算子で複数行を連結するやり方もありますが、これもベストなやり方とは言いがたいです。

    var greeting = "Yo " +
    "World";

そこで、テンプレート文字列を使えば複数行に渡る文字列を簡単に扱うことができます。これは何も特別なことをする必要はなく、以下のように単純に改行するだけです。

    console.log(`string text line 1
    string text line 2`);

ちなみに、バッククォート内の空白は通常の文字列と同じように扱われます。

##タグ付けされたテンプレート文字列

ここまででテンプレート文字列を使って文字列置換と複数行に渡る文字列を扱う方法について見てきましたが、その他の強力な機能として、テンプレートのタグ付け機能があります。タグ付けされたテンプレート文字列を記述するには、テンプレートの前に関数名を配置します。以下に例を示します。

    fn`Hello ${you}! You're looking ${adjective} today!`

上記のタグ付けされたテンプレートは、通常のテンプレート文字列の構文とは異なり、関数呼び出しへと解釈されます。上記のテンプレート文字列の構文糖衣を取り除くと以下のようになります。

    fn(["Hello ", "! You're looking ", " today!"], you, adjective);

注:Nicholas Zakasの『Understanding ES6』では、これらの引数の分解の仕組みについて、さらに詳しく説明されています。

上記の関数呼び出しにおいて、第一引数はテンプレート文字列中のリテラル文字列が格納された配列です。そして二番目以降の引数はリテラルとリテラルの間に挿入される値です。つまり、(n + 1)番目の引数は配列中のn番目と(n + 1)番目の要素のリテラル文字列の間に挿入されます。この機能は様々な用途が考えられますが、最も容易に想像できるものは、挿入された変数の文字列に対してエスケープ処理を施すというものです。

例えばHTMLの文字列を自動的にエスケープするテンプレートは以下のようになります。

    html`<p title="${title}">Hello ${you}!</p>`

このテンプレート文字列では変数の値がそのまま展開されるのではなく、HTMLで使用できない文字をエスケープ処理した上で挿入されます。では実際にそのようなコードを書いてみましょう。ここで、ユーザ名とコメントを引数として受け取るテンプレートを想定してください。両方の引数とも、HTMLで使用できない文字、すなわち(')、(")、(<)、(>)、そして(&)を含む可能性があります。例えば、"Domenic Denicola"というユーザ名と、"& is a fun tag"というコメントが入力された場合、以下のような出力となります。

    <b>Domenic Denicola says:</b> "&amp; is a fun tag"

この場合、タグ付けされたテンプレート文字列は以下のように記述されます。

    function html(pieces) {
        var result = pieces[0];
        var substitutions = [].slice.call(arguments, 1); 
        for (var i = 0; i < substitutions.length; ++i) {
            result += escape(substitutions[i]) + pieces[i + 1];
        }

        return result;
    }

    function escape(s) {
        return s.replace(/&/g, "&amp;")
                .replace(/</g, "&lt;")
                .replace(/>/g, "&gt;")
                .replace(/'/g, "&#39;")
                .replace(/"/g, "&quot;");
    }
    
    var username = "Domenic Denicola";
    var tag = "& is a fun tag";
    console.log(html`<b>${username} says</b>: "${tag}"`);
    //=> <b>Domenic Denicola says</b>: "&amp; is a fun tag"

エスケープ以外にも、文字列整形、ローカライズ等、その他あらゆる複雑な文字列処理をタグ付けの機能を使って行う事ができます。

    // より高機能なエスケープ処理
    qsa`.${className}`;
    safehtml`<a href="${url}?q=${query}" onclick="alert('${message}')" style="color: ${color}">${message}</a>`;

    // ローカライズと文字列整形
    l10n`Hello ${name}; you are visitor number ${visitor}:n! You have ${money}:c in your account!`

    // HTML/XMLの埋め込み
    jsx`<a href="${url}">${text}</a>` // React.DOM.a({ href: url }, text)に変換される

    // コマンド実行するためのDSL
    var childProcess = sh`ps ax | grep ${pid}`;

##まとめ

テンプレート文字列はChromeベータ版のバージョン41以上、IEの開発者プレビュー版、Firefoxバージョン35以上、そしてio.jsで使用可能です。その他にもTracuerや6to5のような主要なES6トランスパイラでサポートされているため、それらを使えば今すぐにでもプロダクションの環境で使用することが可能です。Chrome のサンプルリポジトリに テンプレート文字列のサンプルがありますので、実際に試したい場合はこちらをお使いください。また、ES6とES5のコード比較を見ることで、テンプレート文字列と同等の機能をES5で実現するにはどうすればよいか理解できると思います。

テンプレート文字列はJavaScriptにたくさんの重要な機能をもたらします。それにより、文字列や式の挿入が可能になり、複数行に渡る文字列を扱うことが容易になり、また、独自のDSLを定義することができるようになります。

最も重要な機能はテンプレートのタグ付けの機能であり、それによりDSLを作成することができます。テンプレート文字列の一部を引数として受け取り、それらに対して任意の処理を行った後に置換することで、最終的な出力を自身で決定する事ができます。

##参考文献

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.