JavaScriptの不可解な挙動たち
はじめに
この記事はKogakuin Univ Advent Calendar 2019 18日目の記事です。 adventar.org
みなさんおはこんばんにちは。どうも、Sugiです。Advent Calenderの記事をかけと言われたものの、書ける && マトモな内容がなかったので、
というタイトルで記事を書くことにしました。 18日に…出せるだろうか…
で、どんな事書くのか
とりあえず、この↓画像をご覧あれ。これは、WebブラウザでF12押すと出てくるアレのConsoleタブでひとつの式を実行した際のスクリーンショットです。
ブラウザのコンソールにおいて、左端に > と表示された行に式を入力すると、その下の <・ と表示された行に入力した式の返り値が表示されますね。というわけで、このスクリーンショットは、 [[][+[]]+[]][+[]][+[]]
の返り値が "u" だということを表しているわけです。
は???[と]と+だけでどうやって文字を生成した??そもそもこの式どうなってんだ??
ということで、この式がどうなってんのか、そしてこれに類似した挙動、またそれを利用してこんなこともできるよ(やろうと思えばできるよってだけで、何もいいことないけど)っていうのを解説していこうと、おもんまぁーーーす!!思います。
とりあえず、あの式どうなってんだ
先程の式 [[][+[]]+[]][+[]][+[]]
を、[ と ] の対応がわかりやすいようにインデントして行を分けると
[ [] [ +[] ] +[] ] [ +[] ] [ +[] ]
[ と ] の対応はそれぞれ
1行目 ⇔ 7行目
3行目 ⇔ 5行目
8行目 ⇔ 10行目
11行目 ⇔ 13行目
となっています。
JavaScriptにおいても多くの言語と同じように、[ と ] で囲まれたものは配列であり…というのは、この記事を見ている人たちには解説不要でしょうから省略。というわけで上のコードを見てみると… [ と ] (そろそろこいつら書くの飽きたんでいい略しかた無いかな)で囲まれた部分は、2~6、9、10行目の3つに別れます。2次元配列?? さて、一つめのブロック、2~6行目に関して見ていきましょう。
[] [ +[] ] +[]
は????
まぁ分かる人にはわかるんでしょうけども…配列の要素へのアクセスらしく行で書くと、
[][+[]] +[]
うーん…とりあえず、空の配列に添字として +[]
をつけてるようです。 +[]
とは…?空の配列に+…?そして空の配列の +[]
番目…???
というわけで、2枚目のスクショをどうぞ。
このスクショを見ると、+[]
は0
として評価されることがわかります。
これはどういうことか…JSにおいて、文字列sに符号として+
をつけて+s
とするとNumber(s)
、-s
だと-Number(s)
した値が返ってきます。そして文字列ではない値にこれらの符号を付けた場合、これを文字列に変換したもの (配列の他多くのオブジェクトの場合、.toString()
でこれが得られる) がs
に入ります。
では、[]
を文字列に変換すると? 答えから言うと、""
(空の文字列) になります。なぜかといえば、配列を文字列に変換すると、以下のような方法で文字列に変換されるからです。(完全なコードではないです><)
function toString(array){ var s = ""; for(var i=0; i < array.length; i++){ s += array[i]; if(i < array.length-1){ s += ","; } } return s; }
また、4行目において取り出した配列の各要素が文字列ではない場合、その度に文字列に変換されます。もうお気づきだと思いますが、配列が空の場合はfor文が一度も回らないので、空の文字列が返ってきます。
…えーっと、どこまで解説したっけ? あ、+[]
の[]
が""
になるところまで。つまり、+[]
は+""
と同じであり、これはNumber("")
と等価であり、これが0と解釈されるのです。これらを踏まえて、先程の2つめのコードブロックのうち4行目までは、[][0]
となります。JSにおいて配列の範囲外参照をするとundefined
が返って来ます。要素数が0の配列の0番目は存在しないので、これもundefined
となります。では、その後に続く+[]
。これはさっきと同じで0だ!…ではなく、それは符号として+
や-
をつけた時の話で、足し算・引き算の場合(記号の前に何か値がある時)はそうでは有りません。じゃあundefined + []
はどうなるのよ?それは[]
が文字列に変換されて空文字になり、undefined + ""
と等価になります。そしてこれは…文字列になり"undefined"
になります。
最初のコードブロックの2~4行目が"undefined"
になったので、それを置き換えて1行で書くと ["undefined"][+[]][+[]]
となります。何度も言ったように+[]
は0になるので、["undefined"][0][0]
となります。["undefined"][0]
で長さ1の配列["undefined"]
から0番目の要素を取り出して"undefined"
となるので、それに[0]
をつけた["undefined"][0][0]
は"undefined"[0]
となり、これは"undefined"
の0番目の文字、つまり"u"
となるのです。
↑この段落長すぎ…
とりあえず謎は解けたね
最初に紹介したコード(?)がどうしてuになるのか、これはわかったかと思います。次は、これを応用してこんな事もできるよ!ってのを紹介していきます。
もっとキモいやつ
ごめんなさい今はここまでしかできてません…近日中に出します!