ちょっと詳しくJavaScript 特別編【悪霊の神々】
2011年07月08日




                           株式会社ランチェスター
                           TEL: 03-5775-3395 Fax:03-5775-3396
                           URL: http://www.lanches.co.jp/
名前空間的なもの - 序説
JavaScriptにおける関数定義、変数、クラス的なものなどはすべて何か
のオブジェクトのプロパティとして保持されるため、普通に宣言してしま
うと全てグローバルオブジェクトに属してしまう。
そのため、ライブラリなどで同じ名前があると「後勝ち」してしまい、意図
しない動作を引き起こすことがある。
これを避けるため、グローバルオブジェクトへの定義(汚染)を少なくする
テクニックが生み出された。

それが「名前空間」。

他言語における名前空間、また次世代で検討されているECMAScriptと
しての名前空間とは全く別なので注意してください。



             Proprietary and Confidential to Lanchester Co.,LTD.   Page 1
名前空間的なもの - 実践その1
実はそんなに難しい話じゃないです。

js1.js
function hello() { alert("Hello!"); }

js2.js
function hello() { alert("HELLO!!!"); }

こんなソース2つを読み込むと読み込む順番によってhello関数が上書
きされてしまう。
読み込みの順番を既定したり命名ルールで避ける方法もあるけど、外
部ライブラリを使う場合にはそうも行かないことが・・・



                       Proprietary and Confidential to Lanchester Co.,LTD.   Page 2
名前空間的なもの - 実践その2
js1.js
if(typeof(window.lanchester)=="undefined") {
        window.lanchester = {};
}

window.lanchester.one = {
      hello: function() {
               alert("Hello!");
      }
};

グローバルオブジェクトに変数がすでに存在するかを確認し、ない場合
にはオブジェクトを生成する。
その下に(必要に応じて)ライブラリ名を付け、関数を作成していく。
(js2.jsも同様に)
                       Proprietary and Confidential to Lanchester Co.,LTD.   Page 3
名前空間的なもの - 実践その3
使用する際はそのまま

lanchester.one.hello();
lanchester.two.hello();

となる。

最上位の「lanchester」プロパティのみがグローバルオブジェクトに置か
れ、被害(?)が最小限になる。




                      Proprietary and Confidential to Lanchester Co.,LTD.   Page 4
無名関数作成即実行
関数を作って即実行、その関数は使い捨てたい。
var a = function(){ … };
a();
でもこうするとインスタンスaが出来ちゃう。勿体ない!!

( function(){ … } )();
これで解決!

関数の中で一時変数をたーくさん使ってもグローバルに置かれないので
いろいろ安心できる!

動作的に意味を持たせたいなー・・・なら
( { init: function(){ … } } ).init();
こんなことも!

                     Proprietary and Confidential to Lanchester Co.,LTD.   Page 5
無名関数作成即実行、実例!?
<style type="text/css">
#t { width: 100%; border-collapse:collapse; }
#t td { border: 1px solid #000; }
#t tr.hover { background: #fcc; }
</style>

<table id="t">
             <tr><td>1-1</td><td>1-2</td><td>1-3</td></tr>
             <tr><td>2-1</td><td>2-2</td><td>2-3</td></tr>
             <tr><td>3-1</td><td>3-2</td><td>3-3</td></tr>
</table>

<script type="text/javascript">
for(var i=0, o=document.getElementById("t").getElementsByTagName("tr"), n=o.length; i<n; i++) {
             o[i].addEventListener("mouseover", (function(_tr) {
                          return function() {
                                        _tr.className = "hover";
                          }
             })(o[i]), false);
             o[i].addEventListener("mouseout", (function(_tr) {
                          return function() {
                                        _tr.className = "";
                          }
             })(o[i]), false);
}
</script>
                                     Proprietary and Confidential to Lanchester Co.,LTD.          Page 6
try~catch~finally
try {
         nothingFunction();             // そんな関数はないのに実行
} catch(e) {                            // エラーオブジェクト
         alert(e);                      // nothingFunction is not defined等
} finally {
         …                              // catchされてもされなくても
         …                              // 確実に実行される
}

エラーオブジェクトは各実装で保持しているプロパティが違うのでcatch
した後の扱い方に困る・・・




                      Proprietary and Confidential to Lanchester Co.,LTD.   Page 7
try~catch~finally、実例
var xhr = null;
try {
         xhr = new XMLHttpRequest();
} catch(e) {
         try {
                 xhr = new ActiveXObject("Microsoft.XMLHTTP");
         } catch(e) {
                 try {
                         xhr = new ActiveXObject("Msxml2.XMLHTTP");
                 } catch(e) {
                         alert("Ajax非対応ブラウザ乙ww");
                 }
         }
}

今ではjQueryとかが勝手に作ってくれるAjax用の通信オブジェクト。
昔はこうやって自分で頑張ってつk(ry
                        Proprietary and Confidential to Lanchester Co.,LTD.   Page 8
try~catch~finallyがあるからにはthrowも
function f() {
        throw "can't find";
}

function g() {
        try {
               f();
        } catch(e) {
               alert(e);
        }
}

任意のオブジェクトをthrowすることができる。


                       Proprietary and Confidential to Lanchester Co.,LTD.   Page 9
JavaScriptにおける継承の例 - 定義
function TV(name) {
         this.name = name;
}
TV.prototype.myName = function() { alert(this.name); }
TV.prototype.watch = function() { alert("Watch TV!"); }


function TVwithDVD(name) {
         this.name = name;
}
TVwithDVD.prototype = new TV(); // ここが肝!
TVwithDVD.prototype.play = function() { alert("Play DVD!") }
TVwithDVD.prototype.record = function() { alert("Recording...") }

継承する場合はprototypeへの親クラス代入をコンストラクタ内に書け
ないので注意。
またコンストラクタを継承するのは難易度が高く、実用的ではない。
                          Proprietary and Confidential to Lanchester Co.,LTD.   Page 10
JavaScriptにおける継承の例 - 実践
var tv = new TV("Panazonic");
var dvd = new TVwithDVD("TOSHIVA");

try {
        tv.myName();   // Panazonic
        tv.watch();    // Watch TV!
        tv.play();     // 実行不可
        tv.record();   // 実行不可
} catch(e) {}    // エラー握りつぶし用(本来は非推奨)

try {
        dvd.myName(); // TOSHIVA
        dvd.watch();   // Watch TV!
        dvd.play();    // Play DVD!
        dvd.record();  // Recording...
} catch(e) {}    // エラー握りつぶし用(本来は非推奨)



                       Proprietary and Confidential to Lanchester Co.,LTD.   Page 11
JavaScriptにおける継承の例 - 雑感
JavaScriptにおける継承は、その用途によって多種多様な方法があり
ます。
今回挙げた例はそのうちの一つでしかないので、必要に応じて適した
形を選択する必要があるので、Google等で
「JavaScript 継承」
などで調べることをお奨めします。

クラスベース言語の継承のような機能を提供してくれるライブラリも存
在します。

また、そもそも関連性が希薄なため「継承を使わない」というのも選択
肢の一つに入れておくと良いかもしれません。



            Proprietary and Confidential to Lanchester Co.,LTD.   Page 12
株式会社ランチェスター
TEL: 03-5775-3395 Fax:03-5775-3396
URL: http://www.lanches.co.jp/

ちょっと詳しくJavaScript 特別編【悪霊の神々】