Panda Noir

JavaScript の限界を究めるブログです。

論理演算子が気になって

x=x||0 このコード、よく見かけますよね。関数の引数の初期値を設定しているコードです(x==falseとなる値をとることが想定されている場合この方法では不十分なのですがそれは又の機会に)。しかしもってこのコード、よく出来ていますが初見では何がなんだかわかりませんよね。今回はこの「論理演算子」の説明です。

 

2015/7/17 追記: 演算子ノ全テで演算子についてまとめてみました。そちらも参照ください。

 

そもそも演算子とは?

演算子、特にここでは二項演算子、とはなんでしょうか。演算子とは演算を表す記号です。たとえば 1 + 2、3 * 4、x = yなどですね。

JavaScriptでは演算子は式と式をとり、値を返します。式というのは1やf()のことです。1 + 2は3を、1 + 2 == 3はtrueを返します。

ちょっと脱線するとifは「true」の時ブロック内を実行するという構文です。だからif (x === 3)というように === や !==、==、!=をつかうのです。そしてifはtrueでもfalseでもないものが投げられた時はそれがtrueに属する値かどうか判別します。つまりif (x)のときifは正しくはif (!!x)と書き直されるわけです。

論理演算子

話を戻します。演算子は値を返すのですからもちろん論理演算子も値を返します。しかし、ここで少しおもしろいことが起きるのです。

JavaScriptの&&と||は短絡評価をします。短絡評価というのは && なら左辺がfalseなら、||なら左辺がtrueならそこで演算を打ち切り値を返すのです。パフォーマンス面からみてとても合理的な選択です。&&の左辺がfalseなら右辺がなんであろうと&&がfalseを返すのは明らかなのですから。

しかし、よく考えてください。x=x || 0 というコードの左辺はBool値とは限りません。1が投げられるかもしれないし'WOW!'が投げられるかもしれません。ということは || は短絡評価できないのでしょうか?

安心してください。ここでJavaScriptのtrueに属する値、falseに属する値が生きるのです。つまり左辺がtrueに属する(1や空でない文字列など)時、||は短絡評価で左辺を返します。左辺がfalseなら右辺を返します。

ここで「ん??」と思われた読者はただしいです。そう、実は論理演算子はBool値を返すのではないのです。if (x === 2 && y === 3)というコードはよく見ると===がBool値を返しているために&&もBool値を返しているだけなのです。衝撃ですね!!

論理演算子は論理演算子ではなかった

というわけでJavaScriptでの論理演算子はBool値以外もとるしBool値以外も返すというもはや「論理演算子」と呼べないような代物だったわけです。

ここから本題

ここでようやく本題に入れます。x = x||0、これだけでも十分おもしろいのですがもっと面白いことができます。例えば x&&(y=3)。!?!?となりますよね。このコードを論理演算子なしで書き換えるとこうなります。 if (x) {y=3}

まず論理演算子||が使われているので||は左辺を評価します。左辺はxです。xがfalseならば短絡評価でxを返します(もっとも、このコードでは返したものを受けるものがないので投げっぱなしですが)。そしてxがtrueのとき。なんと右辺が評価されます!右辺はy=3という式です。

みなさんお忘れかと思いますが=も「演算子」なのです。つまり、y=3は式です。評価が可能なのです。ちなみにy=3は右辺の3を返します。だからx=y=3ということができるわけです(x=(y=3)となるので)。

右辺が評価されるので、yには3が代入されます。これで先ほどの書き換えができるわけがわかりましたね。

だからif (x) {y=3;z=9}はx&&(y=3,z=9)と、if (x !== 3) {y=3;z=9}は x||(y=3,z=9)と書き直せます(JavaScriptでは「 , 」も演算子です)。

重大な勘違い

さて、ここでもう一度演算子について立ち返ります。演算子は式と式を受け取り値を返すのです。だから、 y = 3という「式」は受け取れます。

しかし、演算子はbreakやreturn、whileといった「文」は受け取れません。文はなにも値をかえしませんから。だから、&&と||ですべてのifを置き換えることはできません。たとえばif (x) continueはかきかえることができません。

終わりに

演算子ひとつとっても意外と奥が深いJavaScript(奥が深いというよりは気持ち悪い動作をスマートにするといった感じですが)。みなさんの理解の助けになれたら幸いです。