6時だョ!!全員集合!!

Rails・JavaScrictを中心にアウトプットします。

2021年12月4日 JavaScript (JS Primer) 文字列の組み立て-タグ関数

タグ関数

  • 関数の引数に()で囲ってテンプレートリテラルを渡すとただの文字列として出力されます。

書き方

関数 `テンプレートリテラル`  ←このように()はつけずに呼び出します。

  • タグ関数を利用することで呼び出し時に渡される引数が特殊な形になります。
  • 第一引数は、${}で区切った要素で構成された配列。
  • 第二引数は、${}の中身が要素になった配列です。可変長で受け取りたいため、RestPramatersにします。

以下がタグ関数が渡す特殊な配列の説明のコード例です。

// 呼び出し方によって受け取る引数の形式が変わります。
function tag(strings, ...values) {
    // stringsは文字列のパーツが${}で区切られた配列となります。
    console.log(strings); // => ["template", "literal", ""]
    // valuesには${}の評価値が配列の要素として順番に入ります、
    console.log(values); // => [0, 1]
}
// ()をつけずにテンプレートを呼び出すことでタグ関数が利用出来ます。
tag`template ${0} literal ${1}`;

以下のコード例は引数をどう扱うかを見ていくために、タグつきテンプレートの内容をそのまま結合して返すstringRawというタグ関数をreduceメソッドを用いて実装しています。

function stringRaw(strings, ...values) {    // (`template ${0} literal ${1}`)を渡す
    return strings.reduce((result, str, i) => {
        console.log([result, values[i - 1], str]);
        // 1度目: ["template", 0, "literal"]   
        // 2度目: ["template 0 literal ", 1, ""]
        return result + values[i - 1] + str;
    });
}
console.log(stringRaw`template ${0} literal ${1}`); // => "template 0 literal 1"

こちらのコード例はタグ関数の特殊な配列を返す挙動と、reduceに初期値を持たせないことで特殊な挙動が絡んでいるので難しく感じましたので、深掘りした内容を記載していきます。

まず、はじめにreduceの引数の要素には何が入っているのかを確認します。

  • resultにはtemplate
  • strには literal
  • iには 1 が入っています。
    どうしてreduceの要素にはこの3つが入るのかを理解するにはreduceの第二引数である初期値を持たせていない挙動を理解していないといけません。

初期値あり

ループ周目 result str i
1 0 1 0
2 1 2 1
3 3 3 2
4 6 4 3

初期値なし

ループ周目 result str i
1 1 2 1
2 3 3 2
3 6 4 3
4 10 5 4

初期値あり 初期値なし
result 初回ループのときは初期値が入る・2周目以降は処理結果(returnされた値)が入る 初回ループのときに配列の最初の要素が入る・2周目以降は同左
str 配列の最初の要素から順に入る 配列の2番目の要素から順に入る
i strで処理されている要素のインデックス 同左

  • 今回は初期値がなしの挙動なので、1周目では、resultが0番目の要素、つまりtemplateとなり、i にはstrのインデックスが 1 であるから1 が入ることで、values[1-1]が行われ、valuesのindex0番目の要素である0が入ります。strには、2番目の要素"literal"が配列に追加されています。

 return result + values[i - 1] + str;
1周目の結果 "template 0 literal"

2周目で入る引数は以下になります。

resultにはtemplate 0 literal strには 空白 iには 2

2周目のreturnの式はこのようになります。

 return  template 0 literal  + values[2 - 1] + str;

こちらが計算式が成り立つことで得られる結果が

template 0 literal 1

となり、タグ関数の文字の結合をreduceを用いてできました。

reduceのポイント

  • reduce関数は第一引数にコールバック関数、第二引数に初期値を設定することができます。
  • 今回の例では初期値を設定していません。それにより、初回のループが暗黙的に行われます。​(最初の要素が入ります。)

参照

JSprimer 文字列の組み立て
reduceの初期値ありなしの挙動の違い