Posted at

タグ付きテンプレート(tagged template strings)でなんちゃって演算子オーバーロード

More than 3 years have passed since last update.


はじめに


  • ES2015(ES6)で追加されたタグ付きテンプレート(tagged template strings)



  • その実体は特殊な関数


    • ぱっと見は関数に見えない



  • それをつかって”なんちゃって”演算子オーバーロードをやってみようという記事


    • ※注:実用性は低いです




前提:「演算子オーバーロード」とは

JavaScript(ECMAScript)には無い概念。

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])の方が見やすい!?




一応メリット


補足


valueOfを使った疑似演算子オーバーロード


Reflect.defineOperator





  1. エラーはSIMD型の定義が無いから。simd.d.tsをDLしてください。