<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>仮ぶろぐ &#187; tips</title>
	<atom:link href="http://plusb.jp/blog/?cat=8&#038;feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://plusb.jp/blog</link>
	<description>今更なことをそれでもつらづらと書くブログ</description>
	<lastBuildDate>Tue, 07 May 2013 09:06:48 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>JavaScriptの遅延ロード</title>
		<link>http://plusb.jp/blog/?p=758</link>
		<comments>http://plusb.jp/blog/?p=758#comments</comments>
		<pubDate>Fri, 05 Aug 2011 06:21:40 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[dq]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[遅延ロード]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=758</guid>
		<description><![CDATA[久しぶりに今更なネタですが、JavaScriptの遅延ロードについてです。 単純にJavaScriptのコードで動的にスクリプトを読み込みたいだけならオンデマンドにScriptタグをDOMに追加するだけですみます。 とこ &#8230; <a href="http://plusb.jp/blog/?p=758">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>久しぶりに今更なネタですが、JavaScriptの遅延ロードについてです。<br />
単純にJavaScriptのコードで動的にスクリプトを読み込みたいだけならオンデマンドに<code>Script</code>タグをDOMに追加するだけですみます。<br />
ところが、遅延ロードありきでライブラリやらを構築し出すと、読み込み完了している必要があるだとか依存関係だとかの問題が発生するわけです。<br />
<span id="more-758"></span><br />
これから説明するコードは拙作のライブラリ(<a href="http://plusb.js/dqfw/js/dq.js">dq.js</a>)から抜粋しています。</p>
<h3>とりあえず遅延ロード</h3>
<p>スクリプト内から動的にスクリプトをロードする<code>include()</code>関数の例です。</p>
<pre>
    include = function (file) {
        var s = document.createElement('script');
        s.src = file;
        s.type = 'text/javascript';
        s.defer = 'defer';
        document.head.appendChild(s);
    }
</pre>
<p>このコード自体はなんでも無いですね。<code>script</code>タグをheadタグに追加しているだけです。</p>
<h3>ロード完了を待つ</h3>
<p>そして読み込み完了を待って、任意のコードを実行する<code>lazyLoad()</code>を実装します。</p>
<pre>
    lazyLoad = function(url, ctl, fn) {
        function _check(ctl) { <span style="color:Red;">//オブジェクトの有無でロード完了を判定</span>
            return !!(eval(ctl));
        }
        if (_check(ctl)) {
            fn &#038;&#038; fn(); <span style="color:Red;">//ロード済みなら指定の関数をすぐ実行</span>
        } else {
            include(url);
            setTimeout(function () {
                if (!_check(ctl)) {
                    setTimeout(arguments.callee, 15.625);
                } else {
                    fn &#038;&#038; fn();<span style="color:Red;">//読み込みが終わったら関数を実行</span>
                }
            }, 15.625);
        }
    }
</pre>
<p>今でもそうだと思うのですが、scriptタグの読み込み完了イベントは拾えないので代わりに遅延ロードしたスクリプトを実行した結果として作成されるオブジェクトの有無を判定に利用します。<br />
後は既に読み込み済みなら遅延ロードを実行しないようにチェックを挟んでおきます。</p>
<h3>複数箇所からの呼び出し</h3>
<p>先のコードではとりあえず読み込み済みのチェックは実施していますが、遅延ロードが完了する前に複数回同じスクリプトが呼び出されると無駄があったり面倒くさいことが発生するかもしれません。<br />
そこで同じスクリプトに対しては一度しかinclude()が呼び出されないようにします。</p>
<pre>
    _urls = [];
    lazyLoad = function (url, ctl, fn) {
        function _check(ctl) {
            return !!(eval(ctl));
        }
        if (_check(ctl)) {
            fn &#038;&#038; fn();
            _remove$lazyLoad();
        } else {<span style="color: Red;">
            if (_urls[url]) { <span style="color: Red;">//リクエスト済みならfnのみ登録して終了。</span>
                _urls[url].push(fn);
                return;
            }
            _urls[url] = [];</span>
            include(url);<span style="color: Red;">
            _urls[url].push(fn);</span>
            setTimeout(function () {
                if (!_check(ctl)) {
                    setTimeout(arguments.callee, 15.625);
                } else {<span style="color: Red;">
                    for (var i = 0; i < DQ._urls[url].length; i++) {
                        _urls[url][i] &#038;&#038; DQ._urls[url][i].call();
                    }
                    delete _urls[url];</span>
                }
            }, 15.625);
        }
    }
</pre>
<p>読み込み中のスクリプトと読み込み完了時に実行される関数を<code>_urls</code>に追加しています。<br />
`</p>
<h3>複数のスクリプトを遅延ロードする</h3>
<p>複数のスクリプトを遅延ロードしてから自身のコードを実行したい場合どうなるのでしょうか。</p>
<pre>
lazyLoad("first.js", "Window.FIRST", function() {
  layzLoad("second.js", "Window.SECOND", function() {
      ... //自分のコード
  });
});
</pre>
<p>もしくは</p>
<pre>
lazyLoad("first.js", "Window.FIRST");
layzLoad("second.js", "Window.SECOND", function() {
    ... //自分のコード
});
</pre>
<p>まあ、どちらもいまいちですね。<br />
そこで、全ての遅延ロードが完了したら呼び出される、<code>afterLoad()</code>という関数を用意します。</p>
<pre>
    lazyLoad = function (url, ctl, fn) {
        function _check(ctl) {
            return !!(eval(ctl));
        }
        if (_check(ctl)) {
            fn &#038;&#038; fn();
            <span style="color:red;">__remove$lazyLoad();</span>
        } else {
            if (_urls[url]) {
                _urls[url].push(fn);
                return;
            }
            _urls[url] = [];
            include(url);
            _urls[url].push(fn);

            setTimeout(function () {
                if (!_check(ctl)) {
                    setTimeout(arguments.callee, 15.625);
                } else {
                    for (var i = 0; i < _urls[url].length; i++) {
                        _urls[url][i] &#038;&#038; _urls[url][i].call();
                    }
                    delete _urls[url];
                    <span style="color:red;">_remove$lazyLoad();</span>
                }

            }, 15.625);
        }
<span style="color:red;">_
        function _remove$lazyLoad() {
            var cnt = 0;
            for (var nm in DQ._urls) {
                cnt += _urls.hasOwnProperty(nm) ? 1 : 0;
            }
            if (cnt == 0) {
                __trigger &#038;&#038; setTimeout(DQ.__trigger, 0);
            }
        }
    }

__trigger = function () {
    for (var i = 0; i < _onLoad.length; i++) {
        _onLoad[i].call();
    }
    _onLoad.length = 0;
    delete __trigger;
}
_onLoad = [];
afterLoad = function (callback) {
    _onLoad.push(callback);
}</span>
</pre>
<p>使い方は以下の通りです。</p>
<pre>
lazyLoad("first.js", "Window.FIRST");
layzLoad("second.js", "Window.SECOND");
afterLoad(function() {
    ... //自分のコード
});
</pre>
<p>より複雑なケースでは問題が出る可能性もありますが、そこは宿題ということで。</p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=758</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>calleeの使い道</title>
		<link>http://plusb.jp/blog/?p=472</link>
		<comments>http://plusb.jp/blog/?p=472#comments</comments>
		<pubDate>Thu, 25 Mar 2010 12:45:15 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[プログラミング]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=472</guid>
		<description><![CDATA[常に今更な内容ですが、色々コードを読んでいて見つけたarguments.calleeの使い方のパターンを書き留めておきます。 非同期の完了待ち 一定の条件が成立するまでタイマーで待機するパターンです。例えばJavascr &#8230; <a href="http://plusb.jp/blog/?p=472">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>常に今更な内容ですが、色々コードを読んでいて見つけたarguments.calleeの使い方のパターンを書き留めておきます。</p>
<h3>非同期の完了待ち</h3>
<p>一定の条件が成立するまでタイマーで待機するパターンです。例えばJavascript等の遅延読み込みの完了待ち等です。</p>
<pre>setTimeout(function() {
    if (完了条件) {
        完了時の処理
    }
    <span style="color: #00ffff;">arguments.callee</span>();
}, 15.625);</pre>
<p>これなら汎用の関数がかけますね</p>
<pre>function wait(condition, callback) {
    var _condition = (typeof condition == "string") ?
                     function() { return eval(condition); } : condition;
    if (_condition()) {
        callback &amp;&amp; callback();
    }
    setTimeout(function() {
        if (_condtion()) {
            callback &amp;&amp; callback();
        }
        <span style="color: #00ffff;">arguments.callee</span>();
    }, 15.625);
}</pre>
<p>使い方はこんな感じ</p>
<h4>foo.js</h4>
<pre>FOO = {}
FOO.bar = function() {
    alert("Hellow");
}</pre>
<h4>JavaScriptの遅延ロード</h4>
<pre>var s = document.createElement('script');
s.src = "foo.js";
s.type = 'text/javascript';
s.defer = 'defer';
document.getElementsByTagName('head').item(0).appendChild(s);
wailt("FOO", function() {
   FOO.bar();
});</pre>
<h3>再帰呼び出し</h3>
<p>どうもこれが最も典型的な使い方みたいですね。</p>
<pre>function Factorials(x) {
    if (x &lt;= 1) {
        return 1;
    }
    return x * <span style="color: #00ffff;">arguments.callee</span>(x - 1);
}</pre>
<p>ただし、もっと本質的には無名関数である必要がありますが･･･</p>
<ul>
<li><a href="https://developer.mozilla.org/ja/Core_JavaScript_1.5_Reference/Functions/arguments/callee">calle &#8211; MDC</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=472</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaScriptでObject要素を操作する</title>
		<link>http://plusb.jp/blog/?p=339</link>
		<comments>http://plusb.jp/blog/?p=339#comments</comments>
		<pubDate>Fri, 26 Feb 2010 04:20:48 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[プログラミング]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=339</guid>
		<description><![CDATA[JavaScritpでオブジェクト要素のdata属性を変更しようとすると、ieだけうまく参照先を変更してくれません。 どうも、object要素自体を置き換える必要があるようです。 まずは正しく変更出来ない（ieのみ）パタ &#8230; <a href="http://plusb.jp/blog/?p=339">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>
JavaScritpでオブジェクト要素のdata属性を変更しようとすると、ieだけうまく参照先を変更してくれません。<br />
どうも、object要素自体を置き換える必要があるようです。
</p>
<p><span id="more-339"></span></p>
<p>
まずは正しく変更出来ない（ieのみ）パターンです。
</p>
<pre>
function(id, url) {
  var o = document.getElementById(id);
  o.setAttribute('data', url);
}
</pre>
<p>
data属性は変わっているようですが、ieだと変更されたurlを表示してくれません。<br />
これを、object要素のクローンを作成指定リプレースするとちゃんと新しい要素を反映してくれます。</p>
<pre>
function(id, url) {
    var obj = document.getElementById(id);
    obj.setAttribute('data', url);
    var clone = obj.cloneNode(true);
    obj.parentNode.replaceChild(clone, obj);
}</pre>
<p>
jQueryを使用した場合も示しておきます。</p>
<pre>
function(id, url) {
    var obj = $('#' + id).attr('data', url);
    obj.replaceWith(obj.clone(true));
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=339</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaScript流Strategyパターン</title>
		<link>http://plusb.jp/blog/?p=294</link>
		<comments>http://plusb.jp/blog/?p=294#comments</comments>
		<pubDate>Thu, 11 Feb 2010 17:58:32 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[プログラミング]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=294</guid>
		<description><![CDATA[今思いついたのだけれど、JavaScript流のStrategyパターンとは直接メソッドを書き換えることじゃないだろうか。 Context = function() { this.foo = ConcreateA.foo &#8230; <a href="http://plusb.jp/blog/?p=294">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>
今思いついたのだけれど、JavaScript流のStrategyパターンとは直接メソッドを書き換えることじゃないだろうか。
</p>
<p><a href="http://plusb.jp/blog/wp-content/uploads/2010/02/58dee91c.png"><img src="http://plusb.jp/blog/wp-content/uploads/2010/02/58dee91c-300x68.png" alt="" title="58dee91c" width="300" height="68" class="alignnone size-medium wp-image-298" /></a></p>
<pre>
Context = function() { this.foo = ConcreateA.foo; }
Context.prototype.foo = function() {}
ConcreateA.foo = function() {
//実態
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=294</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javascript Arrayの継承</title>
		<link>http://plusb.jp/blog/?p=95</link>
		<comments>http://plusb.jp/blog/?p=95#comments</comments>
		<pubDate>Sat, 06 Feb 2010 11:52:33 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[継承]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=95</guid>
		<description><![CDATA[Arrayの継承、実はモダンブラウザ(ie7を除く）だと、ほぼ旨くいくんですね。 function extend(s, c) { function f() {}; f.prototype = s.prototype; / &#8230; <a href="http://plusb.jp/blog/?p=95">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Arrayの継承、実はモダンブラウザ(ie7を除く）だと、ほぼ旨くいくんですね。<br />
<span id="more-95"></span></p>
<pre>
function extend(s, c) {
  function f() {};
  f.prototype = s.prototype; <span style="color:Red">//sはインスタンスでは無く、型でなければだめ</span>
  c.prototype = new f();
  c.prototype.__super = s.prototype; <span style="color:Red">//オーバーライド用に保持</span>
  c.prototype.constructor = c;
  <span style="color:Silver;">...</span>
}
Collection = extend(Array, function() {
  if (arguments.length == 1 &#038;&#038; typeof n == "number") {
     return;
  }
  for (var i = 0; i &lt; arguments.length; i++) {
    this.push(arguments[i]);
  }
  Collection.prototype.join = function(separator) { //オーバーライド
      return this.__super.join.apply(this, arguments);
  }
});

foo = new Collection (1,2,3);
foo.push(4);
foo.push(5);
</pre>
<p>実際の実行結果は以下のとおり</p>
<div id="result" style="border: 2px solid Silver; width: 3em;"></div>
<p><script type="text/javascript">
function extend(s, c) {
  function f() {};
  f.prototype = s.prototype;
  c.prototype = new f();
  c.prototype.__super = s.prototype; <span style="color:Red">//オーバーライド用に保持</span>
  c.prototype.constructor = c;
  <span style="color:Silver;">...</span>
}
Collection = extend(Array, function() {
  if (arguments.length == 1 &#038;&#038; typeof n == "number") {
     return;
  }
  for (var i = 0; i < arguments.length; i++) {
    this.push(arguments[i]);
  }
});</p>
<p>foo = new Collection (1,2,3);
foo.push(4);
foo.push(5);
document.getElementById('result').innerHTML = "[" + foo.join(',')  + "]";
</script></p>
<p>
本文の最初で「ほぼ」旨くいくとお茶を濁している原因がコンストラクターの部分でプリミティブなオブジェクトの<br />
コンストラクターを継承先から呼び出しても期待通りの振る舞いをしてくれません。自作のクラスを継承した場合は<br />
<code>this.__super.constructor.aply(this, arguments);</code>とすれば旨くいくのですが・・・</p>
<p>
そこで今回は強引に渡された引数を自前で<code>push</code>しています。
</p>
<p>それからもう一つ、直接要素を指定した場合に<code>length</code>が正しく反映されません。</p>
<pre>
var c = new Collection(1,2,3);
c[3] = 4;
alert(c.length); <span style="color:Red;">//期待値は4</span>
</pre>
<p>最後にie7でも上記２点以外を対応される方法（力業）を示します。</p>
<pre>
function extend(s, c) {
  function f() {};
  if (s == Array) {
      var a = new s;
      f.prototype.constrctor = s;
      f.prototype.concat = a.concat;
      f.prototype.join = a.join;
      f.prototype.length = a.concat;
      f.prototype.pop = a.pop;
      f.prototype.push = a.push;
      f.prototype.reverse = a.reverse;
      f.prototype.shift = a.shift;
      f.prototype.slice = a.slice;
      f.prototype.sort = a.sort;
      f.prototype.splice = a.splice;
      f.prototype.unshift = a.unshift;
  } else {
      f.prototype = s.prototype;
  }
  c.prototype = new f();
  c.prototype.__super = s.prototype; <span style="color:Red">//オーバーライド用に保持</span>
  c.prototype.constructor = c;
  <span style="color:Silver;">...</span>
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=95</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>メンバー変数ではなくてプロパティーについて</title>
		<link>http://plusb.jp/blog/?p=115</link>
		<comments>http://plusb.jp/blog/?p=115#comments</comments>
		<pubDate>Tue, 02 Feb 2010 00:40:41 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[property]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=115</guid>
		<description><![CDATA[JavaScriptにはpublicやprivate等の概念は無いですがやはり、private相当の属性にはgetterやsetterを提供してやりたくなります。 余談ですが、プラべーメンバーの隠蔽はコンストラクター内で &#8230; <a href="http://plusb.jp/blog/?p=115">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>
JavaScriptには<code>public</code>や<code>private</code>等の概念は無いですがやはり、<code>private</code>相当の属性にはgetterやsetterを提供してやりたくなります。<br />
<span id="more-115"></span><br />
余談ですが、プラべーメンバーの隠蔽はコンストラクター内でクロージャーを使用すれば実現可能ですが他のメンバー関数からも<br />
直接参照出来なくなるので好みではありません(命名規則などのルールで拘束すれば十分だと思ってます）。
</p>
<p>
で、getterやsetterの実装を考えると高級言語によくあるpropertyは良くできた仕様です。<br />
内部的にsetterを定義しないか<code>readonly</code>を宣言すれば参照のみ出来るメンバー変数のできあがりです。
</p>
<pre>
[C#]
{
 private int foo_;
 property int foo {
     get { return foo_; }
 };
</pre>
<p>getter,setterの実装をどうするか考えた結果、採用(別に私のオリジナルではありません）したのが以下の方法です。</p>
<pre>
Class = function() { this._foo = 0; } <span style="#1111EE">//privateメンバーは'_'で始める</span>
Class.prototype.foo = function (value) {
    if(!arguments.length) {
        return this._foo;
    } else {
        this._foo = value;
    }
}
</pre>
<p>
実用上これで問題ないですが、.Net Framework のPropertyGridやXmlSerializerを実装しようとすると機械的にgetter,setterの<br />
有無を確認できる方が都合が良いです。かといって getFoo() 等にするのは嫌・・・。
</p>
<p>
で、あいだととってgetter,setterをプライベート相当で定義することにします。</p>
<pre>
Class.prototype.__foo = {}
Class.prototype.__foo.get = function() {
   return this._foo;
}
Class.prototype.foo = function (value) {
    if(!arguments.length) {
        return this.__foo.get();
    } else {
        this.__foo.set(value);  <span style="#1111EE">//エラー処理は割愛</span>
    }
}
</pre>
<p>
まあ、これを一つ一つ書くのは面倒なので関数を用意します。</p>
<pre>
function __property__(object, name, get, set, def) {
    var _nm = "_" + name;
    var __nm = "__" + name;
    object.prototype[_nm] = def || false;
    object.prototype[__nm] = { 'get': get, 'set': set };
    return function (value) {
        if (!arguments.length) {
            !this[__nm].get &#038;&#038; throw new Error('has not getter');
            return this[__nm].get.apply(this);
        } else {
            !this[__nm].set &#038;&#038; throw new Error('has not setter');
            this[__nm].set.apply(this, arguments);
        }
    };
}
Class.prototype.foo = __property__(
    Class,
    "foo", 
    function() { return this._foo; }, 
    null , 
    "hoge");
</pre>
<div style="font-size: 120%;">
・・・やり過ぎかなorz
</div>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=115</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaScriptの継承を実装する</title>
		<link>http://plusb.jp/blog/?p=102</link>
		<comments>http://plusb.jp/blog/?p=102#comments</comments>
		<pubDate>Tue, 02 Feb 2010 00:40:09 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[継承]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=102</guid>
		<description><![CDATA[JavaScriptには継承の機能が無い（代わりにプロトタイプチェーンを使用して同等の機能を実現する）わけですが、一つ自分好みの継承関数を実装してみたいと思います。 ソース:inherit.js 前提はこれくらいでしょう &#8230; <a href="http://plusb.jp/blog/?p=102">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>JavaScriptには継承の機能が無い（代わりにプロトタイプチェーンを使用して同等の機能を実現する）わけですが、一つ自分好みの継承関数を実装してみたいと思います。<br />
ソース:<a href="http://plusb.jp/dqfw/labo/js/inherit.js">inherit.js</a>
</p>
<p><span id="more-102"></span></p>
<p>前提はこれくらいでしょうか</p>
<ol>
<li>オーバーライド時に継承元の関数が呼び出せる</li>
<li>多階層の継承が出来る</li>
<li>C++でのvirtualな呼び出しが出来る</li>
</ol>
<p>C++やC#をずっと使ってきた自分にとってはプロトタイプチェーンだけではVB6のClassのような残念感があります。<br />
やはりポリモーフィズムやオーバーライドが出来ないと逆に不便です。<br />
色々な継承パターンを調べてみましたが、extendパターンが自分向きのようです。</p>
<p>まずは単純なextend関数</p>
<pre>
function extend(s, c)
{
    function f(){};
    f.prototype = s.prototype;
    c.prototype = new f();
    c.prototype.__super = s.prototype;
    c.prototype.__super.constructor = s;
    c.prototype.constructor = c;
    return c;
};
</pre>
<p>いきなり余談ですが、JavaScriptではインスタンスも拡張できるので以下のような書き方が出来れば、メタクラスの概念も導入できそうですが、<br />
私は使わないので考慮しないことにします。
</p>
<pre>
MetaClass = function() {}
Class = new MetaClass() {}  <span style="color: #1111EE;">//クラスはメタクラスのインスタンス</span>
SubClass = extend(Class, function() {
});
</pre>
<p>閑話休題。<br />次にコンストラクターをC#やVB.Netの雰囲気で呼び出せるようにbaseメソッドを追加します。</p>
<pre>
function extend(s, c)
{
    function f(){};
    f.prototype = s.prototype;
    c.prototype = new f();
    c.prototype.__super = s.prototype;
    c.prototype.__super.constructor = s;
    c.prototype.constructor = c;
    <span style="color:#1111EE">c.prototype.base = s;</span>
    return c;
};
</pre>
<p>と、これをやると多層継承で嵌ります。</p>
<pre>
a = function() {}
b = extend(a, function() {
  this.base(); <span style="color:#1111EE">//ここのthisがクラスbを指し続けてしまう。</span>
});
c = extend(b, function() {
  this.base();
});
var foo = new c();
</pre>
<p>なのでbaseを関数で実装する</p>
<pre>
function extend(s, c)
{
    function f(){};
    f.prototype = s.prototype;
    c.prototype = new f();
    c.prototype.__super = s.prototype;
    c.prototype.__super.constructor = s;
    c.prototype.constructor = c;<span style="color:#1111EE">
    c.prototype.base = function() {
      var ob = this.base;
      this.base = s.prototype.base;
      s.apply(this, arguments);
      if( this.constructor == c) {<span style="color:Red;">//baseを一回しか呼べないように削除しておく</span>
          delete this.base;
      } else {
          this.base = ob;
      }
    }</span>
    return c;
};
</pre>
<p>次はメソッドのオーバーライドです。以下のやり方では、bでオーバーライドしたbarが期待通り呼び出されません。</p>
<pre>
a = function() {};
a.prototype.foo = function() { 
  this.bar();　<span style="color: #1111EE;">//bのbarを読んでくれません。</span>
}
a.prototype.bar = function() {
  this._bar = "bar";
}

b = extend(a, function() {
  this.base();
});
b.prototype.foo = function() {
  this.__super.foo();
}
b.prototype.bar = function() {
　this.__super.bar();
  this._bar += "b";
}

var hoge = new b();
hoge.foo();
</pre>
<p>これは、<code>this.__super.foo();</code>を<code>this.__super.foo.apply(this,arguments);</code>とすることで解決します。
</p>
<p>ところが、この記述は<code>base</code>と同様に多層継承での問題をはらんでいます。<br/><br />
結局、ここについては専用の関数を提供することにしました。</p>
<pre>
__super__ = function(me, m, a) {
    a = a || [];
    var b = me.__super;
    var r,s;
    if (b &#038;&#038; b[f] == me[f]) {
        for (s = me.__super.__super; s &#038;&#038; s[f] == me[f]; s = s.__super) {
            ;
        }
    } else {
        s = b;
    }
    if (s == null) {
        throw new Error("__dqsuper__: 循環呼び出しか、継承されていないオブジェクトから呼び出されました。");
    }
    me.__super = s.__super;
    r = (typeof f == "string") ? s[f].apply(me, a) : f.apply(me, a);
    me.__super = b;

    return r;
}
</pre>
<p>一応完成形</p>
<pre>
function extend(s, c, m) {
    function f(){};
    f.prototype = s.prototype;
    c.prototype = new f();
    c.prototype.__super = s.prototype;
    c.prototype.__super.constructor = s;
    c.prototype.constructor = c;
    c.prototype.base = function() {
      var ob = this.base;
      this.base = s.prototype.base;
      s.apply(this, arguments);
      if( this.constructor == c) { 
          delete this.base;
      } else {
          this.base = ob;
      }
    }
    <span style="color: #1111EE">//属性を拡張</span>
    for (var n in m) {
        c.prototype[n] = m[n];
    }
    return c;
}
</pre>
<p><a href="http://plusb.jp/dqfw/labo/inherit.html">デモ</a><br />
<a href="http://plusb.jp/blog/?p=95">JavaScript Arrayの継承について</a></p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=102</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavascriptのNaNを判定</title>
		<link>http://plusb.jp/blog/?p=62</link>
		<comments>http://plusb.jp/blog/?p=62#comments</comments>
		<pubDate>Mon, 18 Jan 2010 09:01:01 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=62</guid>
		<description><![CDATA[isNaN()について、どうも間違った説明をしているところが多いようですね（ググってて混乱しました）。 NaNは==や===に対して常にfalseを返すため、parseInt()の返値がNaNかどうかを判定するのにisN &#8230; <a href="http://plusb.jp/blog/?p=62">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>isNaN()について、どうも間違った説明をしているところが多いようですね（ググってて混乱しました）。<br />
NaNは==や===に対して常にfalseを返すため、parseInt()の返値がNaNかどうかを判定するのにisNaN()を使用するわけですが、isNaN()は「NaNかどうか」では無く「数値に変換できるかどうか」を判定しているらいしいですね。<br />
なので以下のような結果になるようです<br />
<code><br />
isNaN(null); //false(nullは0扱い)<br />
isNaN(10); //false<br />
isNaN('10'); //false<br />
isNaN('abc'); //true<br />
isNaN(NaN); //true<br />
isNaN(undefined); //true(数値には変換できない)<br />
isNaN('10px'); //true<br />
</code></p>
<p>実験:</p>
<pre>
<script type="text/javascript">
document.writeln('isNaN(null) : ' + isNaN(null));
document.writeln('isNaN(10) : ' + isNaN(10));
document.writeln('isNaN("10") : ' + isNaN("10"));
document.writeln('isNaN("abc") : ' + isNaN("abc"));
document.writeln('isNaN(NaN) : ' + isNaN(NaN));
document.writeln('isNaN(undefined) : ' + isNaN(undefined));
document.writeln('isNaN("10px") : ' + isNaN("10px"));
document.writeln('isNaN(parseInt("10px")) : ' + isNaN(parseInt("10px")));
</script>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=62</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VS2010 が起動できない</title>
		<link>http://plusb.jp/blog/?p=59</link>
		<comments>http://plusb.jp/blog/?p=59#comments</comments>
		<pubDate>Mon, 18 Jan 2010 08:26:30 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[tips]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[vs2010]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=59</guid>
		<description><![CDATA[突如として Visual Studio 2010ベータ版が「The application cannot be started.」といって起動出来なくなった。 結局、コマンドプロンプトからdevenv /resetuse &#8230; <a href="http://plusb.jp/blog/?p=59">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>突如として Visual Studio 2010ベータ版が「The application cannot be started.」といって起動出来なくなった。<br />
結局、コマンドプロンプトから<code>devenv /resetuserdata</code>とすることで解決した。</p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=59</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>文字列のソート</title>
		<link>http://plusb.jp/blog/?p=28</link>
		<comments>http://plusb.jp/blog/?p=28#comments</comments>
		<pubDate>Thu, 14 Jan 2010 18:03:06 +0000</pubDate>
		<dc:creator>M. K.</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[sort]]></category>
		<category><![CDATA[string]]></category>

		<guid isPermaLink="false">http://plusb.jp/blog/?p=28</guid>
		<description><![CDATA[文字列の配列のカスタムソートを実現したいと思ったらsort関数に独自の比較関数を指定するわけですが、C#などの間隔で以下の用の式を書いて躓いてしまいます。 var names = srt.sort(function (a &#8230; <a href="http://plusb.jp/blog/?p=28">続きを読む <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>文字列の配列のカスタムソートを実現したいと思ったらsort関数に独自の比較関数を指定するわけですが、C#などの間隔で以下の用の式を書いて躓いてしまいます。<br />
<code></p>
<pre>
var names = srt.sort(function (a, b, x, y) {
    x = a.charAt(0) == "_" ? a.substring(1) : a;
    y = b.charAt(0) == "_" ? b.substring(1) : b;

    return x - y;
});
</pre>
<p></code><br />
string型は引き算できないので比較した結果を返してやる必要があります。<br />
<code></p>
<pre>
    return (x == y) ? 0 : (x < y ? -1 : 1);
</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://plusb.jp/blog/?feed=rss2&#038;p=28</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
