即時関数を使ってカプセル化しよう

目次

作成したJavaScriptの問題点

前回、JavaScriptでスムーススクロールを実装しましたが、実際にWebサイトで使うにはいくつか問題があります。

そのひとつとして、使っている変数が、他のJavaScriptに影響をしてしまう問題があります。

他のJavaScriptで同じ名前の変数や関数があると、読み込む順番によっては自分の変数の値が他のJavaScriptの処理で意図しない値に書き換わったり、他で使われている変数を上書きしてしまうことがあります。

自分だけがWebサイトを構築して、完全に読み込むJavaScriptを把握していれば回避できるかも知れません。

しかし、人間とは間違うものです。うっかり対応を忘れて変数名が重なってしまい、エラーが発生して対応に頭を悩ますことになるでしょう。

また、複数人でWebサイトに関わることがあれば、配布されているJavaScriptを使うこともあります。そうなればより複雑な状況になって手に負えなくなります。

そこで、カプセル化です。

データと関数を一つのコンポーネント (例えば、クラス) に閉じ込め、そのコンポーネントへのアクセスを制御することにより、そのオブジェクトを “ブラックボックス” にすることです。

https://developer.mozilla.org/ja/docs/Glossary/Encapsulation

変数や関数を閉じ込めて(カプセル化)、他に影響が出ないようにする手法を使うと、他のJavaScriptに影響されず、また影響することを防ぐことができます。

そのカプセル化を実現するために、即時関数を使ってみましょう。

即時関数でカプセル化

即時関数は、正式には「即時実行関数式」と呼ばれ、定義されるとすぐに実行されるJavaScriptの関数のことです。

スムーススクロールは指定した要素の中にあるリンクを探して、クリックされたらスムースにページをスクロールさせるという機能のため、JavaScriptが読み込まれたタイミングで実行された方が良いですね。

関数の中でvarによる変数宣言すれば、その関数の中だけのローカル変数となりますから、他のJavaScriptの変数に影響を与えることも、受けることもありません。

では、この即時関数を使って、スムーススクロールを改修してみましょう。

スムーススクロールを即時関数に改修

まずは、おさらいです。

前回作成したJavaScriptコードは以下のとおりです。

var $link;
var href;
var target;
var position;

$link = $('#gNav').find('a');

$link.on('click', function () {
  href = $(this).attr('href').replace(/.*(#.*)/g, '$1');
  if ( href === '#' || href === '' ) {
    target = $('html');
  } else {
    target = $(href);
  }
  position = target.offset().top;
  $('body, html').animate({scrollTop: position}, 800, 'swing');
  return false;
});

改めて見ると、変数がグローバルで宣言されていることが分かります。

また、その名前もhref, target, positionなど、よく使われる英単語なので、他のJavaScriptに影響が出てしまいそうです。

このコードをカプセル化して、他のJavaScriptに影響が出ないように改修しましょう。

STEP
ページが読み込まれた後で関数を実行する構文を書く

ページの読み込みが完了した後でないと、JavaScriptがスムーススクロールを設定する要素を見つけられず、リンクをクリックしてもスムースにスクロールしません。

jQueryにはDOMの読み込みが完了した後に実行するための記述がありますので、それを使います。

$(function(){
  // ここに処理を書く
});
STEP
即時関数の構文を書く

続いて即時関数の構文を書きます。

$(function(){
  (function(){
    // ここに処理を書く
  })();
});
STEP
即時関数の中に、前回実装したコードを入れます。
$(function(){
  (function(){
    var $link;
    var href;
    var target;
    var position;

    // 中略

  })();
});

この改修で、スムーススクロールで使っていた変数はプライベート変数となり、他でhrefやtargetなどの変数が使われても影響しなくなります。

まとめ

今回改修したJavaScriptは以下のようになります。

$(function(){
  (function() {
    var $link;
    var href;
    var target;
    var position;

    $link = $('#gNav').find('a');

    $link.on('click', function () {
      href = $(this).attr('href').replace(/.*(#.*)/g, '$1');
      if ( href === '#' || href === '' ) {
        target = $('html');
      } else {
        target = $(href);
      }
      position = target.offset().top;
      $('body, html').animate({scrollTop: position}, 800, 'swing');
      return false;
    });
  })();
});

このコードでは問題点や改良点が残っていますが、まずは変数のグローバル汚染を回避するための手法を書いてみました。

自分が書いたコードがうっかり他のJavaScriptに影響して、バグを生み出して解決に時間を取られるなんてことがないように、きちんとしたコードを書けるように気をつけたいものです。

よかったらシェアしてね!

この記事を書いた人

Webコーダーとして日々研鑽しています。
最近はJavaScriptで実現できるギミックが増えることに喜びながら、後方互換に悩むのが日課になっています。

目次
閉じる