JavaScript
TypeScript
ECMAScript

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

More than 1 year has 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してください。