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

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

2021年12月6日 JavaScript (JS Primer) String.raw

String.rawメソッド

String.raw()は、テンプレートリテラル構文から、文字列を取得するメソッドです。 この関数は、テンプレート文字列の生の文字列形式を取得するために使用されます。つまり、置換 (例えば ${foo}) は行われますが、エスケープ (例えば \n) は実行されません。

通常だとテンプレートリテラル構文の中でエスケープを書いたとすると
以下のようにエスケープ処理が行われてしまいます。

function tag(str) {
    // 引数`str`にはただの文字列が渡ってくる
    console.log(str); // => "template 0 literal 1"
}
// ()をつけて関数を呼び出す
tag(`template\n ${0} literal ${1}`);

出力結果
template
${0} literal ${1}

String.rawメソッドを使用すると意図しないエスケープ処理を発生させずに生の文字列を返してくれます。

(例)

console.log(String.raw`template\n ${0} literal ${1}`);  
出力結果
template\n 0 literal 1

[応用]URLエスケープ

タグ関数とreduceで文字列の結合を行っても​意図した通りにURLエスケープすることが出来ます。

(例)

// 変数をURLエスケープするタグ関数
function escapeURL(strings, ...values) {
    console.log(strings); // => [ 'https://example.com/search?q=', '&sort=desc' ]
    console.log(values); // => [ 'A&B' ]
    return strings.reduce((result, str, i) => {
        console.log(result); // => https://example.com/search?q=
        console.log(str); // => &sort=desc
        console.log(i); // => 1
        return result + encodeURIComponent(values[i - 1]) + str;
        console.log(encodeURIComponent(input)); // => A%26B
    });
}

const input = "A&B";
// escapeURLタグ関数を使ったタグつきテンプレート
const escapedURL = escapeURL`https://example.com/search?q=${input}&sort=desc`;
console.log(escapedURL); // => "https://example.com/search?q=A%26B&sort=desc"

JSprimerでのコード例での引数の値をconsole.logで全て出力して、処理の流れを追ったのでそのコードを貼りました。元々のURLの一部分に対してURLエスケープの処理をした上で結合しています。 結果的に文字列と、A&BをURLエスケープした値と、文字列を結合したURLを生の文字列として返しています。

encodeURIComponent関数は引数の値をURLエスケープする関数です。

JavaScriptだと、encodeURI()と、encodeURIComponent()があります。encodeURI()は&と=、/はそのままにするバージョンで、完全なURIを受け取って、そのままURIとして使える文字列を返す想定で、encodeURIComponent()はクエリパラメータで使える安全な文字列(URIの意味を壊さない)を返します。このエントリーでは後者だけを相手にします。

[検証]String.rawメソッドを利用してURLを正しく取得する場合

const input = "A&B";

console.log(String.raw`https://example.com/search?q=${encodeURIComponent(input)}&sort=desc`);

出力結果
https://example.com/search?q=A%26B&sort=desc

車のライトの交換で例えてみました

// ライト交換するタグ関数
// 白いライトに交換するというメソッドがあると仮定します。
function changeLight(car, ...lights) {
    return car.reduce((a, b, c) => {
        return a + 白いライトに交換(lights[c - 1]) + b;
    });
}

const yellowLight = "黄色いライト";
const changedLight = changeLight`黒のボディの${yellowLight}の車`;
console.log(changedLight); // => "黒のボディの白いライトの車"

今回のタグ関数を使った処理をイメージしていたら、車の部品を分解して渡して、ある部品に変化を加えてまた返すというものが浮かんだので書きました。そしてこちらをString.rawメソッドで書くと1行が書くことができます。

console.log(String.raw`黒のボディの${白いライトに交換(yellowLight)の車});

出力結果
"黒のボディの白いライトの車"

参考

JSprimer String.raw

エスケープせず、そのまま文字にしたいならString.raw

encodeURIComponentが世界基準だと誤解してた話