boolean型のif判定：処理の状態をフラグで管理する

##はじめに
プログラミングしているときに、次のような処理を書くことはよくあるかと思います。

**「Aの処理を実行したら、Bの処理を実行する」**

たとえば、「続きを読むボタン」を押したら、続きの文章が表示される・・みたいな処理です。
このような場合、「Aの処理が実行されたか否か」の判定を「フラグ」を使って管理する方法があります。


##フラグってなに？
IT用語としてのフラグとは、「真」か「偽」か、どちらかの値を入れておく変数のことです。
条件が満たされれば「真」、満たされなければ「偽」となります。
JavaScriptではboolean型の変数を使い、真であれば「true」、偽であれば「false」といった真偽値を変数に格納します。
条件が満たされ、フラグが真になることを「フラグが立つ」と表現します。
（「死亡フラグが立つ」という表現に馴染みがある人も多いかと思います）



##boolean型のif判定方法
if文では、条件式の結果がtrue（真）かfalse（偽）かで処理を分岐していくため、条件式部分にそのままboolean型の変数を設定することで処理を分岐していくことが可能です。

```js:js
if((/*boolean型の変数*/) {
    // 条件式部分に設定した変数がtrueの時の処理
    } else {
    // 条件式部分に設定した変数がfalseの時の処理
}
```


##boolean型の変数を条件分岐で判定してみる
###変数がtrueの状態で条件分岐をする場合
たとえば、変数がtrueの状態で条件分岐をする場合は、下記のようになります。

```js:js
var flag = true;

if(flag) {
    console.log('trueです。');
} else {
    console.log('falseです。');
}
```

実行すると、コンソールに下記のメッセージが出力されます。

```
trueです。
```

###変数がfalseの状態で条件分岐をする場合
同じ要領で、変数がfalseの状態で条件分岐をする場合は、下記のようになります。

```js:js
var flag = false;

if(flag) {
    console.log('trueです。');
} else {
    console.log('falseです。');
}
```

実行すると、コンソールに下記のメッセージが出力されます。

```
falseです。
```


##ボタンをクリックした後、表示されたコンテンツ内の要素をスクロールに合わせてフェードインさせてみる
今度は、急に少し難易度上がりますが、実際に案件で私が実装した処理についてご紹介します。

ざっくりとした処理の流れは、下記になります。
①ボタンをクリックし、コンテンツを表示する
②コンテンツが表示されてから、スクロールに合わせてコンテンツ内の要素をフェードインさせる

上記の②の処理を実装するとき、大いにてこずってしまいました・・
そんな私を救ってくれたのが、**「処理の状態をフラグで管理すること」**だったのです・・！

CodePenで実装した完成形は下記なので、イメージしながらこの先をお読みいただければと思います。
また、今回のテーマはJavaScriptの記述についてなので、HTMLとCSSのコードについての説明は省略させていただきます。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="XWeKReK" data-user="suzuy" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/suzuy/pen/XWeKReK">
  アコーディオンボタン押してから中の要素をフェードイン</a> by Suzu (<a href="https://codepen.io/suzuy">@suzuy</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


###うまくいかなかった記述
はじめに私は、下記のように実装しました。

```js:js
var windowHeight;
var scrollTop;

//HTML要素の読み込みが完了したときに実行
$(function() {
    getWindowHeight();

    //ボタンをクリックしたら、コンテンツを表示
    $('.btn_more').on('click', function() {
        $(this).next().slideDown();
    }); 
});

//スクロール時に実行
$(window).on('scroll', function() {
    scrollTop = $(window).scrollTop();  //スクロール量を取得
    scrollHandler(scrollTop);
});

//ページのすべてのリソースの読み込みが完了したときとウィンドウサイズ変えたときに実行
$(window).on('load resize', function() {
    getWindowHeight();
});


//ブラウザの高さを取得する関数
function getWindowHeight() {
    windowHeight = $(window).height();
}

//コンテンツ内の要素を表示する関数
function showContent($obj) {
    $obj.addClass('is-show');  
}

//スクロールにあわせて要素をフェードインさせる関数
function scrollHandler(scrollTop) {
    $('.js-fade-in').each(function () {
        //フェードインさせる要素の位置を取得
        var targetElementOffsetTop = $(this).offset().top;

        //要素の位置までスクロールしたらフェードイン
        if (scrollTop > targetElementOffsetTop - windowHeight) {  // - ＊1
            showContent($(this));
        }
    });
}
```


この書き方の場合に問題となるのは、＊1の条件式です。
この記述では、要素をフェードインさせる条件として「要素の位置までスクロールしたとき」のみとなっています。
そうすると、例えばボタンをクリックせずにそのまま通り過ぎてから、再度ボタンの位置に戻ってクリックしたときには、コンテンツ内の要素がフェードインされず、すでに表示された状態になってしまいます。

ボタンをクリックしてコンテンツが表示されてから、コンテンツ内の要素をスクロールに合わせてフェードインさせるためには、「要素の位置までスクロールしたとき」の条件に加え、**「ボタンをクリックしてコンテンツが表示されたとき」**の条件も加える必要があります。

しかし、どうやって条件を追加すればいいかわからず、私は途方に暮れておりました・・。
そして、上司に助けを求めたのでした。
懇切丁寧に教えていただいた成果が次になります。


###フラグを使って修正してみる
ここで、**「ボタンをクリックしてコンテンツが表示されたか否か」の状態を判定するために、フラグを使います。**
ボタンをクリックしてコンテンツが表示されたときには「true」を、それ以外の場合は「false」をフラグに入れ、＊1の条件式にも記述を追加します。

修正後のコードが下記になります。

```js:js
var flag_open = false;  //フラグの変数宣言時にfalseを設定
var windowHeight;
var scrollTop;

$(function() {
    getWindowHeight();

    $('.btn_more').on('click', function() {
        $(this).next().slideDown();
        flag_open = true;  //ボタンをクリックしコンテンツを表示後、フラグを立てる
    }); 
});

$(window).on('scroll', function() {
    scrollTop = $(window).scrollTop();
    scrollHandler(scrollTop);
});

$(window).on('load resize', function() {
    getWindowHeight();
});


function getWindowHeight() {
    windowHeight = $(window).height();
}

function showContent($obj) {
    $obj.addClass('is-show');
}

function scrollHandler(scrollTop) {
    $('.js-fade-in').each(function () {
        var targetElementOffsetTop = $(this).offset().top;

        //フラグが立っているかつ要素の位置までスクロールしたらフェードイン
        if (flag_open && scrollTop > targetElementOffsetTop - windowHeight) {
            showContent($(this));
        }
    });
}
```

無事、期待通りの動きになりました！
一緒に解決してくださった上司に心の底から感謝です。


##最後に
処理の状態をフラグで管理・判定することで、一見条件分岐が複雑そうな処理も書きやすくなるかも〜という希望をもつことができました。（時と場合によるかもしれませんが）
私自身の復習と、同じように悩んでいる人たちの助けになれば・・と思い、この記事を書きました。

最後までお読みいただきありがとうございました。よいクリスマスを〜！\（^^）/


##参考にさせていただいたリンク
* https://techacademy.jp/magazine/48769
* https://www.sejuku.net/blog/23300