◆ Unicode の ID_Start から始まって ID_Continue が続く
  ◆ Other_ID_Start と Other_ID_Continue も含む
◆ $ と _ もおっけい
◆ 2文字目以降なら <ZWNJ> と <ZWJ> の制御文字もおっけい
◆ \uXXXX の Unicode 形式にもできる

JavaScript で正規表現を使って JavaScript の変数名として使用可能な文字が判断したいことがありました

a~z と A~Z と _ と $ のどれかから始まって 2文字目以降は最初の文字に数字も使えるようになったものが好きなだけ続くでいいかなー と考えていましたが よくよく考えると 日本語も使えます
var あ = 1
var イ = あ
console.log(あ * イ)
// 1

だって普通にいけます

どうせなら日本語もちゃんとチェックしたいな と思って変数に使える文字を ECMAScript 2016 の仕様から探してきました
IdentifierName::
     IdentifierStart
     IdentifierName IdentifierPart

IdentifierStart::
     UnicodeIDStart
     $
     _
     \ UnicodeEscapeSequence

IdentifierPart::
     UnicodeIDContinue
     $
     _
     \ UnicodeEscapeSequence
     <ZWNJ>
     <ZWJ>

UnicodeIDStart::
     any Unicode code point with the Unicode property “ID_Start”

UnicodeIDContinue::
     any Unicode code point with the Unicode property “ID_Continue”

一文字目は UnicodeIDStart か $ か _ か Unicode エスケープされた文字
二文字目以降は UnicodeIDContinue か $ か _ か Unicode エスケープされた文字 か <ZWNJ> か <ZWJ>

と決まってるようです


UnicodeIDStart と UnicodeIDContinue は Unicode には色々なプロパティがあって対応する文字が決められているので その ID_Start と ID_Continue というところをみればいいみたい
ID_Start と ID_Continue はそれぞれ Other_ID_Start と Other_ID_Continue も含むようです

other の方には「ぱ」とかの 「゜」も含まれるので
var ゜ = 1
というコードもおっけいです


Unicode エスケープされた文字はまれに見る これ
var \u0061 = "a"
console.log(a)
// "a"

a は Unicode では U+0061 となるので \u0061 と書いても a となります


<ZWNJ> と <ZWJ> という見慣れないものもありますがこれらは制御文字です
Zero-Width Non-Joiner (U+200C) と Zero-Width Joiner (U+200D) のことで どちらも何も表示されませんが前後の文字列を結合させるかさせないかという情報を持っています
そのままですが Non-Joiner はくっつけない Joiner はくっつける です

英語の PDF をコピペしてくると f と l や f と f がくっついていて別文字になってちゃんと翻訳されない ってときがありますけどああいうくっついた文字をつくるときに使うものなようです

正規表現

この情報を参考に正規表現を作ってみると
var re = new RegExp(String.raw `^(?:\p{ID_Start}|\p{Other_ID_Start}|\$|_|\\u[0-9a-fA-F]{4})(?:\p{ID_Continue}|\p{Other_ID_Continue}|\$|_|\\u[0-9a-fA-F]{4}|${"\u200c"}|${"\u200d"})*$`, "u")

けっこう複雑

だいたいこれでいいはずですが 2 つ問題点があります

1 つ目は Unicode のプロパティを使っているところ
Chrome ではまだ正規表現の u オプションがデフォルトで使えるようになっていないので自分で harmony オプションを起動時のフラグにつける必要があります
--js-flags="--harmony_regexp_property"

これは自分で設定するか待つだけなのでそんなに問題無いです


2 つ目は \u0020 な形式の方で範囲制限してないところ
Unicode のエスケープしたものが使えると言っても 中身は普通な文字なので
var \u002b = 1
はエラーです
u002b は 「+」 記号のことなので構文エラーです

Unicode のプロパティ部分を自分で範囲に置き換えるのは大変だったので省略しました
文字列ならまだ可能性があっても 変数名に Unicode エスケープなんて使わないよね