<?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; 継承</title>
	<atom:link href="http://plusb.jp/blog/?feed=rss2&#038;tag=%E7%B6%99%E6%89%BF" 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 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>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>
	</channel>
</rss>
