JavaScript で String.format したい


他の言語とかで、軽くエラーメッセージ出したい時によく string.format を使うのですが、JavaScript には存在しません。なにかしら似たようなものはないかと Stack Overflow を覗いてみると template literal 使えばっていう回答がありました。テンプレートリテラルとは初耳なので、勉強がてらそれを使ってみることにします。

基礎知識を知りたい時、JavaScript といったら MDN ですね。結論を言うと、template literal は String.Format 的なものではなく、自前で実装するための補助として使います。

template literal (昔はテンプレート文字列と呼ばれていたらしい)の基本的な使い方は以下の通りです。

var id = 1;
var message = `エラーが発生したよ(ID:${id})`;

${} の中に変数とか式を書けるようです。新しい仕様なので古いブラウザでは使えない(=フロントではまだ使いにくい)ですが、Chrome は実装済みのようなので F12 押して Console に入力すれば簡単に試すことができます。他の言語ではよくあるやつが、ようやく JavaScript にも導入された形ですね。

しかし、これは求めていたものとはちがいます。私たちがやりたいのは message を先に用意しておいて、あとから id をいれたいのです。

var message = 'エラーが発生したよ(ID:${0})'; // 色々なところで使いまわしたい
String.format(message, 1); // イメージ(動きません)
String.format(message, 2); // イメージ(動きません)

タグ付けされた template literal

今回必要なのはこちらです。

function template(strings, ...keys) {
  return (function(...values) {
    var result = [strings[0]];
    keys.forEach(function(key, i) {
      var value = values[key];
      result.push(value, strings[i + 1]);
    });
    return result.join('');
  });
}

var errMsgTemplate = template`エラーが発生したよ(ID:${0})`;
errMsgTemplate('1');  // "エラーが発生したよ(ID:1)"

forEach とか rest parameter (可変引数:…keys のような)とか最近のやつ潤沢につかってますね。バニラ JavaScript コーダーにとっては信じがたいコードです。(そろそろ使っていいのかな・・・)

何をしてるのかわかりにくいですが、「タグ関数」に続けて template literal (`~~~`)を続けて書くと、タグ関数が呼び出されます。関数の引数は実際見た方が早いと思います。

strings は配列で、“ で囲まれた文字を ${} で区切った状態になっています。keys は ${} の中身(${100} だと 100、${1 + 2} だと 3)です。この情報を使って、文字列を生成する関数(クロージャ)をタグ関数から返却しています。

function template(strings, ...keys) {
  return (function(...values) {
    var result = [strings[0]];
    keys.forEach(function(key, i) {
      var value = values[key];
      result.push(value, strings[i + 1]);
    });
    return result.join('');
  });
}
var closure = template`IEで使えない${0}を控えてたら、${1}とか${2}(${3})が台頭してきてみんな使ってるし、すごい置いて行かれている気持ち`;
closure('JavaScript', 'node.js', 'TypeScript', 'AltJS')

values[0] は ${0} を置き換え、values[1] は ${1} を・・・といった動きをします。ちなみに、MDNのサンプルは数値のインデックスだけでなく文字列も使える仕組みになっているので、使うのであればそちらが便利です。

String.format のような多機能のものは作れなかったですし、結局自前で作らないといけないのでライブラリ使った方がいいような気もしますが、template literal 自体は文字連結処理が見やすくなるので覚えておいて損はない気がします。


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください