◆ fn `a` で関数が実行されます
◆ String.raw `\n` で \n のまま取り出せます
◆ あとからデータを埋め込むタイプの使いまわせるテンプレートを作りました 

テンプレートストリングで関数が実行される

テンプレートストリングの前に関数があるときにおかしな動きをしていたのを調べてみました
() がなくても関数が実行されてるようです
そのせいで ; 書かない書き方してるとエラーが出てたようです

ですが 関数を普通に実行してるのとは違うようです
var dump = (...args) => {console.log(args)}
var result = dump `abcdefg`
console.log(result)
0: Array[1]
0: "abcdefg"
length: 1
raw: Array[1]
0: "abcdefg"
length: 1
__proto__: Array[0]
__proto__: Array[0]
length: 1
__proto__: Array[0]

undefined
var dump = (...args) => {console.log(args)}
var result = dump `A ${"B"} C${1+1}D${Math.random()}`
console.log(result)
0: Array[4]
0: "A "
1: " C"
2: "D"
3: ""
length: 4
raw: Array[4]
0: "A "
1: " C"
2: "D"
3: ""
length: 4
__proto__: Array[0]
__proto__: Array[0]
1: "B"
2: 2
3: 0.1894653243944049
length: 4
__proto__: Array[0]

undefined

テンプレートへの埋め込みの ${} の前後で文字列が分割されて第一引数に入っています
2 つめ以降の引数は ${} 内が評価された後の値が入ってます


関数の実行は なので 返り値があります
関数の返り値がそのまま受け取れるようです
var result = (()=>"dummy") `abcd`
console.log(result)
dummy


関数の後ろにカッコなしで文字列書いて実行されるって 別の言語使ってるみたいですね

raw

第一引数は配列ですが raw というプロパティが存在しています
上の例では 全く同じものですが エスケープされない特徴があります
((e)=>{console.log(e)}) `ab\tcd\n\nef
g

hij\tkl`
0: "ab cd↵↵ef↵g↵↵h ij kl"
length: 1
raw: Array[1]
0: "ab\tcd\n\nef↵g↵↵h ij\tkl"
length: 1
__proto__: Array[0]
__proto__: Array[0]

raw じゃない方をみると 普通の文字列なので \t や \n はタブや改行に置き換えられてます
raw では \t は \t で \n は \n でそのままです
書いたとおりに取得できます

raw でも直接改行やタブを入力していたものは そのまま改行になっています

なにか作ってみる

その1

便利そうな機能なので何か作れそうです
var raw = e => e.raw[0]
console.log(raw `a\nb\nc`)
a\nb\nc

\n などをそのまま表示できて便利です


ですが ググると String.raw で同じことができるらしいです
String.raw `a\n${1}b\n${2}c`
a\n1b\n2c

ネイティブでやってるなら ${} あってもできるかなとやってみたらできました
String.raw との組み合わせは覚えておくと良さそうです

その2

せっかく作ったのがすでにあったので別のことを考えてみます
考えてみればテンプレートストリングってテンプレートストリングという名前なのにテンプレートを保存しておいて使い回すものじゃなくてその場でテンプレート形式で書いて埋め込むものですよね

じゃあ使いまわせるようにしようか
function Template(parts, ...names){
var obj = {
parts,
names
}
obj.__proto__ = Template.prototype
return obj
}
Template.prototype.generate = function(elements){
if(Array.isArray(elements)){
return this.parts.alternate(elements.slice(0, this.names.length)).join("")
}else{
return this.parts.alternate(this.names.map(e => elements[e])).join("")
}
}

こんな風にテンプレートを作ります
var template = Template `(${"test"}) [${"sample"}] "${"name"}"`

埋め込むときはこんな風に指定した名前のオブジェクトを渡します
var result = template.generate({
test: "てすと",
sample: "さんぷる",
name: "なまえ"
})
console.log(result)
(てすと) [さんぷる] "なまえ"

配列で渡せば前から順に入ります
var result = template.generate([123,456,7890])
console.log(result)
(123) [456] "7890"


便利なんですが 名前がテンプレートストリングなわけですし (その1)の String.raw みたいにまだ私が見つけてないだけでそんな機能ありそうな予感がすごくします


上では省略しましたが 配列を交互にマージする Array#alternate はこんなです
Array.prototype.alternate = function(...arrs){
var res = []
arrs.unshift(this)
for(var i=0, precount=-1;precount!==(precount=res.length);i++){
for(var j=0;j<arrs.length;j++){
var arr = arrs[j]
i < arr.length && res.push(arr[i])
}
}
return res
}

今回限定なら reduce でサッとやってもよさそうでしたが せっかくなので汎用的に使えそうな形にしました