【JavaScript】 便利!テンプレートリテラルとは!だが普及しなそう…
更新日:2023/01/30
JavaScriptにはテンプレートリテラルというものがあります。
使いこなすとめちゃくちゃ便利なので、この機会に覚えておきましょう。
テンプレートリテラルとは
テンプレートリテラルとは、文字列を定義するときに変数を使用したり、ソース上の改行をそのまま取り込めるというもの。
今までは + で連結していたので、コーテーションの記述漏れなどで四苦八苦していました。
今後はテンプレートリテラルを使ってスッキリと書くことができます。
バッククオートで囲む
テンプレートリテラルは、文字をバッククオートで囲みます。
バッククオートとは、コレ → ` です。
どのキーだかわからん!!!
今までほとんど使ったことがないから、バッククオートの位置なんて知らないという人多そうです。
実は僕も以前、バッククオートを入力できなくてテンプレートリテラルの利用をあきらめました。
そうです、テンプレートリテラル普及の最大の障害は、バッククオートが入力できないということなんです!!
僕だけか???
でも今回は、あきらめずに調べました。
JISキーボード
Shiftを押しながら@キーで、バッククオートが入力できます。
USキーボード
Optionを押しながらチルダーキー( ~ )で、バッククオートが入力できます。
変数を使用できる
バッククオートの位置がわかったので、今度からテンプレートリテラルを積極的に使っていけますね!
次はテンプレートリテラルの特徴です。
テンプレートリテラルは、${ 式 }のような書式で式の結果を文字列に取り込むことができます。
この書式は、プレースホルダーと呼ばれることがあります。
変数を使用できる
const obj={
a : "花子",
b : 10,
c : 8
};
const func = ()=>"誕生日";
const text = `今日は${obj.a}さんの${obj.b + obj.c}歳の${ func() }です!${ (function(){return "おめでとうーー"})() }`;
変数だけでなくて、式を使えるという点が便利です。
テンプレートリテラルの中でテンプレートリテラルを使用できる
テンプレートリテラルは入れ子にできます。
const tenki = ["晴れ","あめ","くもり"];
const txt = `明日の天気は${tenki.map( e=> `${ e }かもしれない`).join("...")}...よくわからない`;
console.log( txt);
ソース上のイメージをそのまま文字列にできる
テンプレートリテラルは、途中で改行できます。
その際、改行も文字列に取り込まれます。
const hare = "晴れ";
const ame = "飴";
const txt = `今日は${ hare }
明日は ${ ame }です`;
console.log( txt );
字下げもそのまま取り込まれるので、注意しましょう。
ソースコード上の改行は、次のページを見ると、LF(\n)で取り込まれるようです。
TV excludes the code units of LineContinuation while TRV includes them. <CR><LF> and <CR> LineTerminatorSequences are normalized to <LF> for both TV and TRV. An explicit EscapeSequence is needed to include a <CR> or <CR><LF> sequence.
ECMAScript® 2021 Language Specification
黒い部分の訳:<CR> <LF>および<CR> LineTerminatorSequencesは、TVとTRVの両方で<LF>に正規化されます。
これだけだとTVやTRVが何だかわかりませんが、改行コードがLFに統一(正規化)されるということはわかりますね。
LFで取り込まれているか確認してみます。
const txt = `今日は晴れ
明日は 飴です
明後日はみぞれ煮です`;
console.log( txt);
const rCode ={
"\r\n": "[CRLF]" , "\n": "[LF]" , "\r": "[CR]"
}
const text2 = txt.replace(/\r\n|\n|\r/,
e => `${ rCode[e] }`
);
console.log( text2 );
このページは元々改行がLFなので、当たり前の結果です…
ここで例として出せませんが、CRLFでhtmlを作成して試したところ、LFに変換されました。
タグ付きテンプレートリテラル
テンプレートリテラルが実装されたら、なんだか奇妙なコードを目にするようになりました。
奇妙なコード
function func1( 引数 ){ ...コード };
const text = "プレート";
func1`テン${ text }リテラル`;
関数名の後すぐにテンプレートリテラルが書いてあります。
今まで見たことがない書き方で、タイプミスじゃないのか疑ってしまいますね。
関数`テンプレートリテラル`という形式は、タグ付けされたテンプレートリテラルといいます。
タグ関数
グ付けされたテンプレートリテラルを使用すると、関数に処理途中のテンプレートリテラル配列を渡すことができます。
そのときの関数は、タグ関数と呼ばれることがあります。
function func1( ...param ){
console.log( param );
}
const tenki = ["晴れ","あめ","くもり"];
console.log( ">関数呼び出し" );
func1( `明日は${ tenki[0] }または${ tenki[1] }もしかしたら${ tenki[2] }です`);
console.log( ">タグ付けされたテンプレートリテラル" );
func1`明日は${ tenki[0] }または${ tenki[1] }もしかしたら${ tenki[2] }です`;
上の結果を見ると、カッコを付けてテンプレートリテラルを関数に渡すと文字列に展開されているのがわかります。
一方、タグ付けされたテンプレートリテラルを使用すると、分解されたテンプレートが配列で渡されています。
(補足:func1の...は、レスト構文です)
テンプレートリテラル配列の構造
■インデックス0
インデックス0には、プレースホルダーで分割された文字列が順番に格納されます。
さらにrawという特殊なプロパティを持ちます。
rawは基本的には、インデックス0の内容と同じです。
異なるのは改行などのエスケープ文字の扱いです。
例えば次のようなコードの場合、
func1`行1\n${ 変数 }行2`;
次のようになります。
param[0]=[
0 : "行1↓" // \nが改行コード(16進で0A)に変換されて格納
1: "行2"
raw : [
0 : "行1\n" // \nという文字がそのまま格納
1: "行2"
]
}
param[1] = 変数
変換されない生のデータを使用したいときなど、便利ですね。
■インデックス1~
インデックス1以降は、プレースホルダーの計算結果が格納されます。
タグ付きテンプレートリテラルの目的
タグ付きテンプレートリテラルを使用すると、テンプレートリテラルの評価結果を変更することができます。
function func1( ...param ){
return `${param[0][0]}${ param[1] }ではなくて、男の娘${param[0][1]}`;
}
console.log( `ぼくは${ "男の子" }です`);
console.log( func1`ぼくは${ "男の子" }です`);
同じテンプレートリテラルを使いまわす
テンプレートリテラルは基本的に、その都度記述する必要があります。
しかし次のように、プレースホルダーの内容だけが異なるようなとき、少し無駄を感じてしまいます。
const text1 = `私の名前は${ "太郎" }です`;
const text2 = `私の名前は${ "花子" }です`;
String.rawメソッド
String.rawメソッドを使うと、テンプレートリテラルを使いまわすことができます。
構文
String.raw( テンプレートオブジェクト , 値1 , 値2 ...)
テンプレートオブジェクトは、{ raw: 文字列配列 }を指定します。
2番目以降の引数は、文字列配列の要素間に挿入されます。
const rawObj = {
raw : [ "僕は" , "夢を見た" ]
}
console.log( String.raw(rawObj,"昨日の夜" ) ); // "僕は昨日の夜夢を見た"
上の例は、"僕は" と "夢を見た" の間に"昨日の夜"が挿入されます。
しかし挿入する数が増えると、テンプレートオブジェクトを作成するのがめんどうに感じると思います。
そこで、タグ付きテンプレートリテラルを使用します。
const getTemplate = raw =>{
const rawObj ={raw:raw};
return (...prm)=>String.raw( rawObj , ...prm);
}
const t1 = getTemplate`僕は${ null }夢を見た${ null }`;
console.log( t1( "今日" ,"と思う") );
console.log( t1( "昨日" ,"はずだ") );
${ }内にnullを指定していますが、この値は無視されるので、好きな値で大丈夫です。
これで十分なのですが、もう少し発展させてみます。
各プレイスホルダーに名前を付けて、その名前で表示する文字列を指定できるようにしてみます。
const getTemplate = (raw,...param) =>{
const values = param.map(()=>"");
const rawObj ={raw:raw};
const changeParam = paramList =>{
Object.entries(paramList).forEach(
e=>{
const pos = param.indexOf(e[0]);
if( pos >= 0 ) values[pos] = e[1];
}
);
return values;
}
const func = (prm)=>String.raw( rawObj , ...changeParam(prm));
func.reset = ()=>values.fill("");
return func;
}
const t1 = getTemplate`僕の名前は${ "name" }です。将来の夢は${ "futureDream" }`;
console.log( t1( { name:"太郎" , futureDream:"野球選手" } ) );
console.log( t1( { futureDream:"サッカー選手" } ) );
t1.reset();
console.log( t1({ }) );
${ }内の文字列を、パラメーター名として記憶しておいて、オブジェクトのプロパティ名と照合しています。
また、前回の内容を記憶しておいて、指定されたもののみ変更しています。
まとめ
日本でテンプレートリテラルが普及しない理由は、バッククオートの位置がわからないから。
もうわかったので、これからは積極的に使っていきましょう。
更新日:2023/01/30
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。