はじめに
- ES2015(ES6)で追加されたタグ付きテンプレート(tagged template strings)
- 参考:JavaScript の テンプレートリテラル を極める!
- その実体は特殊な関数
- ぱっと見は関数に見えない
- それをつかって”なんちゃって”演算子オーバーロードをやってみようという記事
- ※注:実用性は低いです
前提:「演算子オーバーロード」とは
JavaScript(ECMAScript)には無い概念。
- 参考: wikipedia
JSで言えば、+
とか-
の演算子(operator)はnumber
(+
はstring
)にしか対応していない所を、例えば配列同士にも対応させようというもの。
実際には”1,2,34,5,6”という結果になる
var sum = [1,2,3] + [4,5,6]
console.log(sum) //[5,7,9]
タグ付きテンプレートリテラル
タグ付きテンプレートリテラル(tagged template strings)とは、通常のテンプレート文字列の前にタグの文字列がついたものだ。
タグ付きテンプレートの例
var str = tag`文字列${変数}`
文字列と呼ばれているが、実は中身は関数へのシンタックスシュガーになっており、returnする中身もstring
である必要はない。
文字数(number)を返すタグ付きテンプレート
"use strict";
function count(a,...args){
let aSum = 0;
a.map((v,i,a)=> aSum += v.length)
let argSum = 0;
args.map((v,i,a)=>{argSum += v.length})
return aSum + argSum
}
var str = "お米"
console.log( count`おいしい${str}` ) //6
タグ付きテンプレートになる関数の特徴
- 第一引数は
raw
というプロパティを持った特別な配列 - TypeScriptでは
TemplateStringsArray
- それ自体、および
raw
プロパティは文字列の配列 - キャッシュされる
- 第二引数以降は、
${}
で括った変数の値がそのまま入る - 文字列に限らない
パッと見、関数に見えないので…
タグ付きテンプレートの特徴を使ってなんちゃって演算子オーバーロードをやってみる。
配列同士の加算
var sum = A`${[1,2,3]} + ${[4,5,6]}`
console.log(sum) //[5,7,9]
Aの中身
function A(arr, a1, a2){
const op = arr[1].replace(/[\s]/g,"");
switch(op){
case "+":
const longer = (a1.length >= a2.length)? a1 : a2
const shorter = (a1.length < a2.length)? a1 : a2
const l = shorter.length
for(let i=0;i<l;i++){
longer[i] = longer[i] + shorter[i]
}
return longer;
break;
default:
throw Error();
}
}
制限
- 上記の例では加算のみ
- 項目が2つまで
- ただし次のようにする事はできる:
A`${[0,1]} + ${ A`${[1,1]} + ${[5,5]}` }`
- 記号が多い
-
A([0,1,2],"+",[3,4,5])
の方が見やすい!?
一応メリット
- 文字列なのでどんな演算子でも自由に定義できる
-
|>
とか - TypeScriptの場合、
valueOf
を使った疑似演算子オーバーロードはエラーになるが、この方法だとならない -
valueOf
の返す型情報を参照しないため - 参考:SIMD型の演算子オーバーロード例1
補足
valueOf
を使った疑似演算子オーバーロード
Reflect.defineOperator
- 提案
- まだES.nextのstage0にすらなってない