無駄と文化

実用的ブログ

【jQueryの基本の"き"】パート3 - 起動スクリプトを囲っているアレをひもとく

さて、前回までjQueryプラグインの基本的な使い方をおさらいして、さらに起動スクリプトについて詳しく解説してみました。

今回は、これまで意図的に触れずにスルーしてきた部分をピックアップします。
起動スクリプトを囲っているよく見るアレ についてです。

さっそく「囲っているよく見るアレ」に登場していただきましょう、はい、

<script>
// ↓よく見る書き方。これが今回の主役です
jQuery(function($) {

  /* ここに起動スクリプトの本体が書かれることが多い */

})
</script>

この書き方、ものすごく重要 なんですがjQueryに馴染まない人はいまいち意味が掴みづらいようです。
「サンプルをそのまま試しているのに何故か動かない」と言うときは、この 囲っているよく見るアレ を使いこなせていない事が多いようです。

さて、


囲っているアレ ファミリー

この 起動スクリプトを囲っているアレ にはいくつかのバリエーションがあります。
微妙に書き方が違うバリエーションがいくつもあるのも初心者が混乱する要因の1つのようです。

起動スクリプトを囲っているアレ の意味を解説する前に、起動スクリプトを囲っているアレ ファミリーを全て並べてみましょう。

<script>
// ========= パターン① ========

// その1
$(document).ready(function() {
  /* ... 起動スクリプト ... */
});

// その2
jQuery(document).ready(function() {
  /* ... 起動スクリプト ... */
});

// その3
$(function() {
  /* ... 起動スクリプト ... */
});

// その4
jQuery(function($) {
  /* ... 起動スクリプト ... */
});

// ========= パターン② ========

// その5
$(window).load(function() {
  /* ... 起動スクリプト ... */
});

// その6
jQuery(window).load(function() {
  /* ... 起動スクリプト ... */
});
</script>

目が回ってきましたか?
大丈夫、なんと1~4は全部同じ意味です。5と6も同じ意味。

なので実際は2種類の書き方だけ覚えればいいんですね。
ここでは仮に、「囲ってるアレ パターン①」「囲ってるアレ パターン②」と呼びましょう。

まずは「書き方のバリエーションはいろいろあるけれど効果は同じなんだ」と理解する事が大切です。


囲っているアレ の効果

お待ちかね、起動スクリプトを囲っているアレ の効果を解説しましょう。

起動スクリプトを囲っているアレ には 起動スクリプトが実行されるのを遅らせる 効果があります。
「ちょっと待って!まだ起動しないで。 (数秒後...)はい、もういいよ。起動スクリプト実行!」とそんな感じに。

「囲ってるアレ パターン①」と「囲ってるアレ パターン②」の違いもそこにあります。

<script>
// ========= パターン① ========

jQuery(function($) {
  /*
   * ここに書かれた起動スクリプトは
   * HTML全体が読み込み終わるまで実行されない。
   **/
});

// ========= パターン② ========

jQuery(window).load(function() {
  /*
   * ここに書かれた起動スクリプトは
   * Windowの読み込みが完了するまで実行されない。
   * HTML全体, 全てのCSS, 全ての画像 の読み込みが終わるまでじっと待つ。
   **/
});
</script>


パターン① と パターン② の違いをお分かりいただけるでしょうか?
それぞれ、HTML の読み込みが終わるまでの間Window の読み込みが終わるまでの間 起動スクリプトが実行されるのを遅らせます。

『なぜ遅らせる?そんな必要ある?』
もっともな疑問ですね。


なぜ HTML の読み込みを待つのか

なぜ 囲ってるアレ を持ち出してまで HTML の読み込みを待たなければいけないんでしょうか。
それは JavaScript は読み込まれた瞬間に実行される からなのですが、ちょっとイメージしづらいと思うので、こんな感じの HTML を書いて読み込ませる例を見てみましょう。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>起動スクリプト サンプルページ</title>

<script src="js/jquery.js"></script>
<script>
$('.target').css({
  color: 'red',
});
</script>

</head>
<body>

<main>
  <h1>起動スクリプト サンプルページ</h1>
  <p class="target">新しい朝が来た、希望の朝だ</p>
</main>

</body>
</html>

jQueryの .css() という機能を使ってターゲットの CSS を書き替えています。
さて、この HTML をブラウザで読み込ませて JavaScript を実行させてみると何が起こるでしょうか?

実は、何も起こりません。


不思議ですね。
実は <head> タグの中に JavaScript を書いているがために、<body> タグ内のターゲット要素を見つけられないのです。

では、HTML が読み込まれる様子をスーパースローカメラでご覧いただきましょう。

f:id:todays_mitsui:20160903221102p:plain

f:id:todays_mitsui:20160903221117p:plain

f:id:todays_mitsui:20160903221141p:plain

f:id:todays_mitsui:20160903221150p:plain

いかがでしょうか?
このスクリプトが期待通りに動かない理由が分かりましたね。


きょう我々はとても重要なことを学びました。
スクリプトが実行されるとき、ターゲットが既にロードされているとは限らないのです。

「JavaScript は読み込まれた瞬間に実行される」とはそう言う意味です。
ブラウザはとてもせっかちなので、ターゲットのロードが完了していなくてもお構いなしです。スクリプトを見つけた瞬間に実行してしまいます。


そこで 起動スクリプトを囲っているアレ ですよ。


HTML の読み込みを待つ意義

反省会が終わったところで先ほどのコードを改良しましょう。

ターゲットのロードが終わってからjQueryのスクリプトが実行されるように、HTML の読み込み完了までスクリプトの実行を待ってもらえばいいのです。
こんなふうに、

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>起動スクリプト サンプルページ</title>

<script src="js/jquery.js"></script>
<script>
jQuery(function($) {

  // これで HTML の全体が読み込まれるまで
  // このスクリプトは実行されない。
  $('.target').css({
    color: 'red',
  });

});
</script>

</head>
<body>

<main>
  <h1>起動スクリプト サンプルページ</h1>
  <p class="target">新しい朝が来た、希望の朝だ</p>
</main>

</body>
</html>

再び HTML が読み込まれる様子を見てみましょう。


f:id:todays_mitsui:20160903221226p:plain

f:id:todays_mitsui:20160903221233p:plain

先ほどの反省を活かして HTML が全て読み込まれたあとでスクリプトを実行しています。
対象である <p class="target"> タグも今回はちゃんと見つかります。

いい感じですね。


「HTML の読み込み」「Window の読み込み」どう違う?

スクリプトの実行をあえて待つことの意義については分かってもらえたと思います。
では 囲っているアレ のパターン①とパターン②の違いについては大丈夫でしょうか?

  • パターン① - HTML が読み込まれるまで待つ
  • パターン② - Window が読み込まれるまで待つ

という違いでしたね。

「HTML の読み込み完了」と「Window の読み込み完了」はどう違うのでしょうか?


Window の読み込み完了は HTML の読み込み完了よりも時間がかかります

「Window の読み込み完了」は CSS や 画像 など 全てのファイルの読み込みが完了した瞬間を意味しているからです。

例えば、HTML を読み込んでいる最中に <link rel="stylesheet" href="style.css"> というような記述があったら、ブラウザはこの「style.css」を追加で読み込みます。
同じように <img src="cat.jpg" alt="My Kitten"> という記述を見つけたら、「cat.jpg」というファイルを追加でサーバーからもらってきます。

f:id:todays_mitsui:20160903221242p:plain

HTML を最終行まで読み終わっても、その中で見つけた CSS や 画像 のダウンロードが完了していなければ Window の読み込み完了とは見なされません。
全ての CSS と全ての画像が読み込まれて、ブラウザ上でページが完全に出来上がった瞬間が「Window の読み込み完了」です。


先ほどは HTML の読み込み完了まで待てば対象の要素が読み込まれているであろうと考えました。

では仮に 対象の画像 を操作するようなスクリプトを実行したいときは?
HTML 読み込み完了時点で 対象の画像 がロードされているとは限りませんよね。その場合は Window の読み込みが完了するまで待ってスクリプトを実行するべきかもしれません。


まとめ

さて 起動スクリプトを囲っているアレ について長々と解説してきました。
今回のダイジェストです。

  • 囲っているアレ は HTML や Window の読み込み完了を待つ
  • スクリプト実行時にターゲットの読み込みが終わっているとは限らない
  • Window の読み込みは HTML の読み込みよりも時間がかかる

これさえ分かればもう怖くないですね。

<script>
// ========= パターン① ========

// その1
$(document).ready(function() {
  /*
   * ここに書かれたスクリプトは
   * HTML の読み込み完了を待って実行される
   * */
});

// その2
jQuery(document).ready(function() {
  /*
   * ここに書かれたスクリプトは
   * HTML の読み込み完了を待って実行される
   * */
});

// その3
$(function() {
  /*
   * ここに書かれたスクリプトは
   * HTML の読み込み完了を待って実行される
   * */
});

// その4
jQuery(function($) {
  /*
   * ここに書かれたスクリプトは
   * HTML の読み込み完了を待って実行される
   * */
});

// ========= パターン② ========

// その5
$(window).load(function() {
  /*
   * ここに書かれたスクリプトは
   * Window の読み込み完了を待って実行される
   * */
});

// その6
jQuery(window).load(function() {
  /*
   * ここに書かれたスクリプトは
   * Window の読み込み完了を待って実行される
   * */
});
</script>

たったのこれだけ!

どれを使えばいいか迷います?
ひとまずは、その4 と その6 を使い分ければ大丈夫ですよ。


私からは以上です。



前回と前々回のリンクを貼っておきます。

blog.mudatobunka.org

blog.mudatobunka.org