c4se記:さっちゃんですよ☆

.。oO(さっちゃんですよヾ(〃l _ l)ノ゙☆)

.。oO(此のblogは、主に音樂考察Programming に分類されますよ。ヾ(〃l _ l)ノ゙♬♪♡)

音樂は SoundCloud に公開中です。

考察は現在は主に Scrapbox で公表中です。

Programming は GitHub で開發中です。

JavaScriptでpackage化 - ライブラリーの書き方(?)

追記 2014-12-19
この記事は大変古いので参考にしないでください。クロージャ (closure) で囲むのは今でもやる場面はあります。node.js (io.js) にはCommonJS由来のmoduleがあり、以下の方法は不要です。Webブラウザには未だ安定したmoduleはありません (ReuireJSやBrowserifyなどはわたしは嫌いです)。ES6 moduleが使へるやうになれば、それを使へるとおもひます。

JavaScriptにはライブラリ等のパッケージ化の方法が無いなどといわれているけど、ちゃんとあるし、ちゃんと使われているよ。(お粗末ではあるけどね。)

基本

とりあえずクロージャに纏める。
(function(){ })();で囲む。

(function(){
  // useful codes
})();

なにが嬉しいか。変数はvarで宣言しておけば、つまりローカル変数で作っておけば、相当無神経なことをしても、ライブラリの外に汚染はない。
勿論速度はわずかに遅くなるはずだ。細心の注意さえ払えばクロージャで纏めなくたってpackage化は出来るが、やはりそれには細心の注意が必要だ。

グローバル変数は最少数にする。

exportするglobal変数は出来る限り少なくする。

(function(){
  var a = 0, b = "bbbbbbbbb";
  gg = {
   a: a,
   b: b,
  };
})();

alert(gg.a + " : " + gg.b);

何がexportされているのかわかりにくい為、読み易くはないが、aとbという二つのlocal変数を、ggという一つのglobal変数に纏められる。

exportを解り易くする方法。

どう見てもわかりやすいよ、という場合はべつによい。僕のこのまえのNaturalクラスhttp://d.hatena.ne.jp/Kureduki_Maari/20090106/1231221669クロージャで括る必要はまったくないのにくるんでるのは、臆病さ故――そんな場合をのぞいて。
まず一つ目、クロージャの引数として与える。

c4sey = {};

(function($y){

var a = "にー";
var fb = function(u){return u;};

$y.gg = {
  a: a,
  b: fb
};

})(c4sey);

alert(c4sey.gg.b(c4sey.gg.a));

jQuery pluginで使われる方法。pi.jsでも。
僕はこの方法を使っている。
そういや「引数」って「ひきすう」なんだね。「いんすう」じゃないんだね。でも喋るときは僕は「いんすう」と言い続ける。


次、クロージャのreturn値を代入。

c4sey = {};

c4sey.gg = (function(){

var a = new Array(0,1,2,3,4,5,6,7,8,9);
var f = function(a){
  return a.map(function(elm){
    return Math.pow(elm, 3);
  });
};

return {
  a: a,
  b: f
};

})();

alert(c4sey.gg.b(c4sey.gg.a));

どっかで見た。どこかはわすれた。

初期化は一回しかしたくない。

よね。
これはif文でチェックするのが一番でしょう。

try{c4sey;}catch(e){c4sey = {};}

(function($y){

if($y.gg) return $y.gg;

$y.gg = {
 a: "くぷくぷ",
 b: function(s){
   return s.split("").join("ー");
 }
};

})(c4sey);

alert(c4sey.b(c4sey.a));

global objectをifで、if(!c4sey) c4sey = {};とやると、ReferenceError: c4sey is not definedとなるので、気を付けましょう。
なんらかのlocal objectの場合――この場合だとc4sey.ggですが――は読み出そうとしてもundefinedを返すだけです。つまり、c4seyが定義されているけどc4sey.ggが無い時は、(c4sey.gg ? true : false);はfalseを返します。undefinedはfalseです。
でもglobal objectだと、ReferenceErrorです。暗黙で宣言してくれたりはしません。だから、try{}catch(){}で捕まえなけりゃなりません。今回はtry{c4sey;}catch(e){c4sey = {};}。

ライブラリ読み込みが無い!

残念でした。読み込みの為のコードを書きましょう。それしかありません。
uupaa.jsscriptaculousのようにライブラリ読み込みを初めからサポートしているものはいいですが、でなきゃ自分で書くしかありません。
<script src=""></script>を書き足せばいいんです。document.write()でもいいし、document.appendChild()でも構わないでしょう。僕はdocument.write()です。読み込み順を心配しないでいいので。
因みに自分自身がどこのフォルダにいるかを調べるコード。

(function(){

var src = "";
var scripts = document.getElementsByTagName("script");
for(var i=0; i<scripts.length; i++)
  if(/c4sey\.js$/.test(scripts[i].src))
    src = scripts[i].src.slice(0, -8);

// lording codes

})();

srcの中にフォルダ名が文字列で入るはずです。c4sey.jsと、slice(0, Number)のNumberを変更すれば、使えるはず。
Ajax読み込みとかは、僕がサーバーを使えないので無視。

自分でグローバル変数の名前を決めたくない。

慎重な皆さん、歓迎です。
でもその前に、

window.["ありえない"] = (function(){
  return {
    a: 0,
    b: ""
  };
})();

などとすることも可能ですよ。JavaScriptはHashTableでできているので、global objectであるwindowにありえないobject名を入れてもいいんです。a = 0とするのはwondow.a = 0とするのと大体いっしょです。(当然違いはありえますが。)


それでも満足できない方。
臆病な皆さん、大歓迎です。
そうですよね。global名までlibrary作者に決めさせるのは負担が大きすぎますよね!――と、そんな場合。
ユーザーに決めさせちゃえ(きゃはっ)。
そうそう。

<script src="lib/c4sey.js?g=$$yy"></script>

とか書かせればいいのよー。
上記のライブラリ読み込みのコードを応用して。

(function(_scope){

var param = {};
var scripts = document.getElementsByTagName("script");
for(var i=0; i<scripts.length; i++)
  if(/c4sey\.js/.test(scripts[i].src)){
    var _e = /(.*)c4sey\.js\?(.*)/.exec(scripts[i].src);
    param.src = _e[1];
    var _param = _e[2].split("&");
    for(var i=0; i<_param.length; i++){
      _param[i] = _param[i].split("=");
      param[_param[i][0]] = _param[i][1];
    }
  }

_scope[param.g] = {
  a: 0,
  b: "",
  c: null,
  d: false,
  e: undefined
};

})(window);

ぎゅっとしてどっかーん!
param.srcに"lib/"、param.gに"$$yy"が入るはず。


あぁ、これを応用すれば、JavaScriptCGI風にパラメータを渡せますね。