Help us understand the problem. What is going on with this article?

ショートサーキット?何それ、美味しいの?という話

あらすじ

Vue.js入門で、ナビゲーションガードをかける実装(10章)に取り組んでいたが、以下のコードで特に矢印の部分が気になった。

※今回の記事で使っている、Vue、Vuex、ナビゲーションガードなどは解説しません

export const authorizeToken= (to,from,next) => {
 if(to.matched.some(record => record.meta.requiresAuth)) {
  if(!store.state.auth || !store.state.auth.token){  これ
    next({ path:'/login' }) // ログイン画面に飛べ
  } else {
    next()} // でなければ次のステップに進め
  } else {
    next()
  }
}

こちら。

  if(!store.state.auth||!store.state.auth.token){

Vuex storeのstateオブジェクトの中身はこちら

Vue.use(Vuex) //ログイン認証用のVuex

const state = {
 auth: { //状態`Auth`
  token: null, //`token`はnullで初期化
  userId: null //`userId`はnullで初期化
},

export default new Vuex.Store({
 state, getters, actions, mutations,
 strict: process.env.NODE_ENV !== 'production'
})

stateオブジェクトの中には、認証tokenとuserIdのセットが入った、authオブジェクトが入っている。これを踏まえて下記の文は、こう読める(直訳)。

  if(!store.state.auth||!store.state.auth.token) { }
// authオブジェクトが有効でないならば(オブジェクトが存在しなければ)、
// もしくは
// authオブジェクトのtoken属性が有効でないならば((値が存在しなければ))
// { }以降を実行せよ(ログイン画面に飛べ)

やりたいことは、ナビゲーションガードだから、「別に両方書かなくても、!store.state.auth.tokenだけで良くない?」と思ったので、先輩エンジニアに聞いてみると「いや、これが正しい」ということだった。どういうこと?

小さなものからパフォーマンスを改善させろ

先輩いわく「アプリケーション開発で必要なのは、いかにパフォーマンスを上げる工夫ができるか?」とのこと。確かに、先の文で言えば、if(!store.state.auth.token){}でもプログラムは動くのだが、論理演算子の特性を活かし、左側を先に書いておけば、プログラムの処理は早くなるとのこと。この、論理演算子の特性の1つが、ショートサーキット。

ショートサーキットって?

左オペランドのみ評価し、右オペランドを評価しないこと。
 
&&演算子と | | 演算子は、左オペランドを先に評価する。
その際左オペランドが、&&演算子はfalse、 | | 演算子はtrueの場合には、右オペランドを評価しない。

つまり「右オペランドの評価を省略する」ため、これを「ショートサーキット」「短絡評価」と言う。また&&演算子と | | 演算子を「ショートサーキット演算子」「短絡演算子」とも言う。

引用:http://www.kab-studio.biz/Programing/JavaA2Z/Word/00001028.html

要は、左側の式を先に評価するという仕組みを活かし、今回のケースで言えば「そもそもauthオブジェクトの中身まで見るまでもなく、authオブジェクトそのものが無効なら(有効でないならば)」と言っておけば、||演算子はTRUEは否定の演算子)を返すので、右側をプログラムは見なくていい、ということだったんですね。

先輩からは、「こういう行間というか、意図を正しく解釈できないとプログラムを正しく書き直すことができないから、細かいけどこういう所も含めてきちんと理解して」とお叱り頂きました😅

補足(2020年11月23日)

今回扱ったこちらのコードに関して、

 if(!store.state.auth||!store.state.auth.token) { }

こちらを、下記のように変えるべきでは?とのご指摘を頂きました。

if(!isObject(store.state.auth) || isNull(store.state.auth.token)) { }

これだと、authはオブジェクトなのかそうでないのかが即座に理解でき、tokennullかそうじゃないのかを判定しているとすぐわかります。では、なぜ、そこまで書き方を工夫する必要があるのでしょうか?

理由は「単に制御構文を書くんじゃなく、プログラマーが一発で何を制御させたいのかわかりやすく明記することで、想定されるバグを未然に防ぎやすくなる」ためです。

今回のケースで言うと「JavaScriptで制御構文を書く時に、False属性で判定させると、それが不具合の温床になりかねない」という点がポイントです。JavaScript の言語仕様として、

  • 条件分岐は、True or False属性で分岐する
  • false0""(空文字)nullundefinedFalse属性である
  • if (!store.state.auth) {}は、if (store.state.auth == false) {}と同じ
    • ==は、JavaScript では勝手にデータ型を変換してしまうので、0 でも "" でもFalseと判定されてしまう

というのがあります。これらのことから、元のコードの場合だと、プログラマーは「authに配列が入ってきたとき、あるいは文字列が入ってきたときに、エラーにならないな?」とか「auth.tokenが、nullじゃなくて、0が入ったときも、動作するんだろうな、、、」など色々考えないといけなくなります。

こういう、プログラマーに考えさせる負担を少しでも減らして分かりやすく表現する力をつけることも、プログラマーとして必要なのだと学びました。@standard-softwareさん、ありがとうございました。

まとめ

他人のコードを読む時に「あれ?なんでこんな風に書いているんだろう?」と考えるシーンが出てくると思いますが、「どんな工夫をしているんだろう?」と想像しながら読んでみると、コードリーディングが楽しくなるのかな〜と思いました。あとは、できる人のプログラムをたくさん読んで、引き続き勉強していきます👊

参考

下記2点追加(2020年11月23日)
- JavaScript の == と === の違いを詳しくまとめてみる
- Quora プログラミングでは、より短いコードで同じ目的を達成した方が、優れているのですか?

sakamiti_46
人材業界で2年、転職コーディネーターと営業事務の業務経験を積んでおります。2020年5月から本格的に学習を始め、10月に自社開発企業でエンジニアとして就職することになりました。日々の学習を通じて得た学びや気付きを記事として投稿致します。どうぞよろしくお願い致します。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away