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

【js簡単纏め】続:javascriptを勉強して恐怖感を取り除こう!~外部化編~

More than 5 years have passed since last update.

概略

効能:javascriptがなんだか使えるような気がしてくる。
対象:なんだか書ける気がしてきたがソースが汚いぞ・・・?

はい。私です。

自分のコードが汚いので、どうやったら綺麗になるのか考えながら、
とりあえず、外部化しないとなと思いまして、こんな記事です。(命名規則とかは各自でやってね☆)

前回の記事はこちら。
javascriptを勉強して恐怖感を取り除こう!

まずは外部化しますか? -> 是非しましょう。

htmlの中に書き続けるのも良いですけど、よくないね。見づらくなるし……
と思って何が悪いのか調べてみると、以下のデメリットがあるそうです。

  • 大量にあると我々が見難い。
  • SEO的に割りと良くない。(html中のjsで機械が困るらしい)
  • 使いまわせない。
  • 処理が重くなる。

何だか一杯有りますね(´・ω・`;)

さて、早速外部化っぽいことしましょう。

example
┗example2.html
┗js - example2.js
┗img - いろんな画像(仮に僕はhut.pngを入れています。)

こんな感じでフォルダを整理していることにしましょう。

example2.html
<!DOCTYPE html>

<html lang="ja">
  <head>
    <!-- ページの文字コード決定 -->
    <meta charset="utf-8">
    <!-- 自分で作ったjavascriptの宣言 -->
    <script type="text/javascript" src="js/sample2.js"></script>
    <title>続:なんとなくJSを使う</title>
  </head>

  <body>
    <section>
      <img id='sample_img' src='' name="img" alt='画像登場予定'/>
      <BUTTON type="button" onClick="drawImg()">画像表示・非表示</BUTTON>
    </section>
  </body>
</html>
js
var c = 0;
function drawImg(){
  var img = document.getElementById("sample_img");
  if(c%2 == 0){
    img.src = 'img/hut.png';
  }else{
    img.src = '';
  }
  c++;
}

こんな感じで、どうでしょう?
動きました?

でもこれ、ちょっと嫌な感じですよね。

僕はなんだか凄い違和感です。

違和感POINT1:
getElementById("sample_img")

違和感ポイント2:
img.src = 'img/hut.png'

まぁ単純な話、ここを引数にしないとjs側から指定している感じしますよね。
ボタンを押したら、表示・非表示を切り替える。そんな単純な機能をいろんな画像でいろんな場所で使いまわすなら、引数にしないと気分悪いですよね。

しかも、画像の指定はhtmlからみたディレクトリの指定方法をしないといけません。jsファイルの中なのに!

ということでこんな感じにしましょう。

<BUTTON type="button" onClick="drawImg()">画像表示・非表示</BUTTON>

この部分を

<BUTTON type="button" onClick="drawImg('img/hut.png', 'sample_img')">画像表示・非表示</BUTTON>
js
var c = 0;
function drawImg(imgPath, imgTag){
  var img = document.getElementById(imgTag);
  if(c%2 == 0){
    img.src = imgPath;
  }else{
    img.src = '';
  }
  c++;
}

これで使いまわせますね!

【即時関数】すぐに動く関数ってあるの?【使ってみよう】

なにかのトリガーで関数を引っ張ってきて使うのはなんとなくわかりますが...
ページ読み込み時に実行するjavascriptが有ればなぁって時有りますよね?

  • このjsを読み込んだ時に、すぐに動かしたい!
  • トリガーとかそういうんじゃ無いんだ。なんていうか、このクラスにしたらそれに全部効いてくれる。そんなやすらぎのようなjsがかけたら嬉しんだ。

htmlに直接書き込めば動いてくれてたのに、外部化したらどーすんのよ!
そんなあなたに 即時関数 なんてどうでしょうか。

(function(){
    //即時関数だよ(・∀・)
})();

こんな感じで関数名を指定しない形で記述すれば良いのです。これで読み込みと同時に関数が走ってくれます。

よく、このクラス名に設定したliタグを記述して下さいとか、そんなjsを使ったことありませんか?
プルダウンメニューとか。

プルダウンメニューではないですけど、こんな感じなのはどうでしょうか。

html
<!DOCTYPE html>

<html lang="ja">
  <head>
    <!-- ページの文字コード決定 -->
    <meta charset="utf-8">
    <!-- 自分で作ったjavascriptの宣言 -->
    <title>続:なんとなくJSを使う</title>
  </head>

  <body>
    <section>
      <p class="autoString">ひとつめ</p>
      <p class="autoString">ふたつめ</p>
      <p class="autoString">みっつめ</p>
      <p class="autoString">よっつめです</p>

      <div id="divWrite"></div>

      <p id="result" class=""></p>
    </section>


    <script type="text/javascript" src="js/sample3.js"></script>
  </body>
</html>

js
//autoStringというクラス名を記述されているタグを配列にして宣言
var autoStringClass = document.getElementsByClassName('autoString');

var divElement      = document.getElementById("divWrite");
var result          = document.getElementById("result");


//即時関数。読み込みと同時に動作。
(function(){
  result.innerHTML = "即時関数スタート";
  //最初にautoStringクラスを持っているタグを非表示にする。
  for(var i = 0; i < autoStringClass.length; i++){
    autoStringClass[i].style.visibility = 'hidden';
  }
  //divの中にautoStringを持ったpタグを書き込む。
  divElement.innerHTML = "<p class=\"autoString\">いつつめだよ!</p>";

  //一秒ごとに実行する。(初回動作も1秒後だよ!)
  setInterval("autoVisibility()",1000);
})();


function autoVisibility(){
  result.innerHTML = "setInterval動作開始";

  for(var i = 0; i < autoStringClass.length; i++){
    if(autoStringClass[i].style.visibility == 'hidden'){
      autoStringClass[i].style.visibility = 'visible';
    }else{
      autoStringClass[i].style.visibility = 'hidden';
    }
  }
}

!!結果はこちら!!

画像1
js2-1.png

画像2
js2-2.png

実行してみた方「いつつめ」だけ点滅のタイミングが違うと思いますが、分かりますか?

for文の後に書き足してるものですから、意図的に最初に隠す処理から逃してあげてタイミングをずらしているんですね。

でもこれちょっと不思議なんですけど。

と思った方いますか?

var autoStringClass = document.getElementsByClassName('autoString')
この部分が変だなぁと思った人もいるかもしれません。

なんで最初に宣言しているのに、後から書き加えた奴もautoVisibility()関数の影響を受けているのか。

という点だと思います。僕もこの記事書いてる時に、ふと気になりました。
でもJavascriptってそういうものなんです。

コンソールに結果を出力する
console.log(autoStringClass);
これを仕込ませてみれば、理由がなんだかわかると思います。

...結果から言いますと、 最初に宣言して4つの配列をautoStringClass変数に代入しているわけではない のです。

あくまで document.getElementsByClassName('autoString') を変数に代入しているのです。

  • 追記:2014/9/8 コメントでもっと腑に落ちる解説をしてくださった方がいました。
getElementsByClassName()は配列ではなく配列のようなインターフェースを持つHTMLCollectionオブジェクトを返します。
HTMLCollectionオブジェクトが都度要素を探す実装になっていれば、後から追加した要素も出てくるようになるというわけです。

参考文献:W3C DOM4

  • 追記終わり

つまり、後から増えようとも対象になるわけです。

不思議ですねぇ。
まだ勉強中ですが、このへんの考え方がクロージャーに似ているのかもしれませんね!(-_-;)

こんなところで今回は終わりです!

俺(達)の勉強はこれからだ!

おまけ

この即時関数。どうやら結構いろんな書き方が有るみたいですね。
昔の記事ですが、ここを参考にしてみてください。
即時関数(function(){ ... })()の別の書き方いろいろ

voidなんて書き方は人によってはこっちのほうがしっくり来る書き方かもしれませんね。

mmusasabi
(*´д`*)パッション!!
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