🐡

ランタイムエラーも避けられまぁす!

2022/03/03に公開約2,300字

ムシャクシャしてやった。今は後悔している(午前中の進捗ぅううう…)

今朝子供の幼稚園の送迎中にちょっと面白そうなツイートを見つけた。

https://twitter.com/uhyo_/status/1498975389905223680

のでスマホ入力で頑張ってレスってみたんだ。

https://twitter.com/kawaz/status/1499180989859659778

少ししてから反応見直してみたらなんか煽られとる…。

https://twitter.com/uhyo_/status/1499186759615541250

出来らぁっ!

まずはコレを見て見てくれ。コレが欲しかったんだろ!? (好きでやってみただけで別に本気で腹が立ったわけではない)

種明かし

種明かしとしては直前に見えない関数を定義することで、欲しい見た目を実現している。全体としてはこんなコード。

// おまじない(見えない関数を定義する)
=ᡸᡸ=>// SyntaxErrorはもちろん、ランタイムエラーすら出さずに実行してる図```
ᡸhi
ᡸ```

更に可視化すると以下のような事をやっている。(見た目調整の為にしていたインデントは省略)

//可視化バージョン
eval("\u{1878}=\u{1878}\u{1878}=>\u{1878}")
eval("\u{1878}```\nhi\n```")

U+1878 の探し方

この話のキモは U+1878 の文字を探し当てたところにある。
ていうか本当にこんな文字(変数の1文字目に使えて不可視)が存在するとは…自分で見つけておきながらビックリだわw(あえて言えば文字幅もゼロor小さいのが希望だったが流石にそれは無かった)

  1. 識別子に使えてかつできるだけ見た目の存在感の無い文字を探せばいけるんじゃね?
  2. とりあえず ECMAScript の Identifier の定義を確認したところ、ユニコードの ID_Start プロパティを持つ文字なら識別子の1文字目として使える事が分かった。
  3. https://util.unicode.org/UnicodeJsps/regex.jsp?a=[%3AID_Start%3A]&b=[:ID_Start:] の文字をとりあえず全部表示してみて見にくい文字を探してみる。
  4. このままだと見にくいので列挙された文字を1文字ずつ分割して [] で囲ったものを縦に並べて文字自体の他に文字幅も確認しやすいよう縦に並べてスクロールしながら目視確認

  5. するとフォントが無いときに表示される豆腐文字ですらなく、完全に空白文字にしか見えない文字を発見した。それが U+1878 だった。他にはこれ以上見えない文字は無さそうなのでコレを使う事にする。

3連テンプレートリテラル対応

ここでは説明の為に U+1878 に置き換えて書く事にする。

  1. まず試しに JS Console で以下を実行してみる→難なく成功
 = () => 1
  1. 次にタグ付きテンプレートとして実行出来るかどうか以下を試す→成功
■`hoge`
  1. 満を持して最初の奴を実行してみる→失敗!
```
hi
```
  1. 3 が失敗した理由は最後の空文字テンプレートに対して 2 の結果として得られた 1 をタグ関数として使おうとしてるせいなだけなので、 の戻り値も関数にしてやれば良い筈って事で以下のように定義を修正する。
 = () => () => 1
  1. 今度こそ行けるだろってことで再実行→出来たー!
```
hi
```
  1. 折角だから関数定義の () の辺りも無駄に不可視化しつつ 自体も自分を返す再帰関数にすることで3段以上のテンプレートリテラルにも対応して完成とした。
 = ■■ =>

ちなみに最初 ■ = ■ => ■ って書いたら、タグ関数として呼ばれたときに に引数が渡されちゃうせいで再帰にならないという凡ミスがあったが引数の変数名を ■■ に修正して回避した。

なお、元ツイートに関数内に入れてる絵もあったので、それもエラー無く実行出来たことをここに示しておく。

Discussion

ログインするとコメントできます