<?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>underscore.js &#8211; Mach3.laBlog</title>
	<atom:link href="https://blog.mach3.jp/tag/underscore-js/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.mach3.jp</link>
	<description></description>
	<lastBuildDate>Mon, 23 Dec 2013 01:33:25 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>
	<item>
		<title>&#034;extend&#034; &#8211; Alphabetical Advent Calendar 2013</title>
		<link>https://blog.mach3.jp/2013/12/23/jaac2013-x-extend.html</link>
		
		<dc:creator><![CDATA[mach3]]></dc:creator>
		<pubDate>Mon, 23 Dec 2013 01:33:25 +0000</pubDate>
				<category><![CDATA[Laboratory]]></category>
		<category><![CDATA[Advent Calendar 2013]]></category>
		<category><![CDATA[extend]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[underscore.js]]></category>
		<guid isPermaLink="false">http://blog.mach3.jp/?p=3785</guid>

					<description><![CDATA[&#8220;X&#8221; は extend の &#8220;X&#8221;。 extend JavaScript で extend というと、幾つかのオブジェクトをマージして拡張する処理の事として知られます。  [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>&#8220;X&#8221; は extend の &#8220;X&#8221;。</p>



<figure class="wp-block-image"><img decoding="async" src="https://lh4.googleusercontent.com/-l3QAKVYOUrk/UqR4nATH8CI/AAAAAAAACYg/QzWinpmaz-4/s400/ac2013-x.png" alt="X"/></figure>



<p></p>



<span id="more-3785"></span>



<h2 class="wp-block-heading">extend</h2>



<p>JavaScript で <strong>extend</strong> というと、幾つかのオブジェクトをマージして拡張する処理の事として知られます。<br />
かなり頻繁に使われるこの機能は、多くのJavaScriptフレームワーク・ライブラリに備えられています。</p>



<p>例えば jQuery の場合は <strong>$.extend</strong> として実装されています。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">var</span> dest = {<span class="hljs-attr">a</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">b</span>: <span class="hljs-number">2</span>};
<span class="hljs-keyword">var</span> src = {<span class="hljs-attr">a</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">c</span>: <span class="hljs-number">3</span>};

$.extend(dest, src);
<span class="hljs-built_in">console</span>.log(dest); <span class="hljs-comment">// {a: 2, b: 2, c: 3}</span>
</code></span></pre>


<p>$.extend は複数のオブジェクトを引数に渡し、先頭に渡したオブジェクトの拡張をします。<br />
その他のフレームワークにおいても基本的な使い方は共通で、<br />
underscore.js の <strong>_.extend</strong> もほぼ同様の記述で利用できます。</p>



<h3 class="wp-block-heading">いくつかのパターン</h3>



<p>extend 機能を実装する上で、いくつかのパターンが考えられます。</p>



<ul class="wp-block-list">
<li>値がオブジェクトだった場合に再帰的にコピー（ディープコピー）するか否か</li>



<li>既に同じ名前のプロパティが存在した場合に上書きするか否か</li>
</ul>



<p>これらは正解不正解なくケースによって使い分ける物だと思いますが、<br />
利用する extend 関数がどのパターンで機能を提供するのかは把握しておいた方が良いでしょう。<br />
特に、ディープコピーの有無によるミスは気づきにくいかもしれません。</p>



<p>ちなみに jQuery はディープコピーの有無をコントロールする事が出来、underscore.js はディープコピーを行いません。<br />
同名プロパティについては両者ともに後から渡された値で上書きを行います。</p>



<h3 class="wp-block-heading">ディープコピーと参照</h3>



<p>コピー元のプロパティの値がオブジェクトであった場合、<br />
それをそのままコピーしてもそれは元のオブジェクトへの参照になります。<br />
例えば次のように src のプロパティに <strong>data</strong> というオブジェクトがぶら下がっているとします。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">var</span> dest = {};
<span class="hljs-keyword">var</span> src = {
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">a</span>: <span class="hljs-number">1</span>,
        <span class="hljs-attr">b</span>: <span class="hljs-number">2</span>
    }
};
</code></span></pre>


<p>この src を元にして dest を拡張してみます。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">$.extend(dest, src);
<span class="hljs-built_in">console</span>.log(dest); <span class="hljs-comment">// {"data":{"a":1,"b":2}}</span>
</code></span></pre>


<p>問題なく拡張出来たように見えますが、<br />
ここでコピー元の src.data のプロパティを変更してみると、それが dest.data にも反映される事が分かります。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">src.data.a = <span class="hljs-number">0</span>;
<span class="hljs-built_in">console</span>.log(dest); <span class="hljs-comment">// {"data":{"a":0,"b":2}}</span>
</code></span></pre>


<p>これは dest.data が src.data に紐付いている為に引き起こる様です。<br />
この時 dest.data を src.data から切り離した新しいオブジェクトとして複製したい場合は、<strong>ディープコピー</strong> を使います。<br />
jQuery の場合は引数の先頭に <strong>true</strong> を足してあげることでディープコピーが出来ます。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">$.extend(<span class="hljs-literal">true</span>, dest, src);
</code></span></pre>


<h3 class="wp-block-heading">同名プロパティの上書き</h3>



<p>あまりないケースかもしれませんが、<br />
コピー先のプロパティを活かしたい場合は引数の最後に渡して改めてコピーする事になります。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">$.extend(dest, src, {
    <span class="hljs-attr">propToProtect</span>: dest.propToProtect
});
</code></span></pre>


<h3 class="wp-block-heading">新しいオブジェクトとして生成する</h3>



<p>継承した結果を新しいオブジェクトとして取得したい場合は、<br />
空のオブジェクトを先頭に渡します。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">var</span> obj = $.extend({}, src1, src2);
</code></span></pre>


<p>src1 / src2 共にプロパティの変更はされず、空のオブジェクトに継承された結果が返り値として返ります。</p>



<h2 class="wp-block-heading">extend の習作</h2>



<p>なんとなく extend の働きを理解したところで、簡単な extend 関数を習作してみます。<br />
まずはシンプルにディープコピー無しの extend です。</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">var</span> extend = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"><span class="hljs-regexp">/* dest, src1, src2 */</span></span>)</span>{
    <span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>, dest, src, name;
    dest = <span class="hljs-built_in">arguments</span>&#91;i++];
    <span class="hljs-keyword">for</span>(; i&lt;<span class="hljs-built_in">arguments</span>.length; i++){
        src = <span class="hljs-built_in">arguments</span>&#91;i];
        <span class="hljs-keyword">for</span>(name <span class="hljs-keyword">in</span> src){
            <span class="hljs-keyword">if</span>(! src.hasOwnProperty(name)){ <span class="hljs-keyword">continue</span>; }
            dest&#91;name] = src&#91;name];
        }
    }
    <span class="hljs-keyword">return</span> dest;
};
</code></span></pre>


<p>次に、ディープコピーの有効・無効をコントロール出来るようにしたタイプです。<br />
（コントロールをなくして別名関数にしてしまった方がシンプルに済むかもしれません）</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-comment">// obj のタイプを文字列で返す</span>
<span class="hljs-keyword">var</span> type = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">obj</span>)</span>{
    <span class="hljs-keyword">var</span> m = <span class="hljs-built_in">Object</span>.prototype.toString.call(obj).match(<span class="hljs-regexp">/\&#91;object\s(\w+)\]/</span>);
    <span class="hljs-keyword">return</span> m ? m&#91;<span class="hljs-number">1</span>].toLowerCase() : <span class="hljs-literal">null</span>;
};

<span class="hljs-keyword">var</span> extend = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"> <span class="hljs-regexp">/* &#91;deep,] dest, src &#91;, src2 ...] */</span> </span>)</span>{
    <span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>, deep = <span class="hljs-literal">false</span>, dest, merge;
    <span class="hljs-keyword">if</span>(type(<span class="hljs-built_in">arguments</span>&#91;<span class="hljs-number">0</span>]) === <span class="hljs-string">"boolean"</span>){
        deep = <span class="hljs-built_in">arguments</span>&#91;i++];
    }
    dest = <span class="hljs-built_in">arguments</span>&#91;i++];
    merge = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">deep, dest, src</span>)</span>{
        <span class="hljs-keyword">var</span> name;
        <span class="hljs-keyword">for</span>(name <span class="hljs-keyword">in</span> src){
            <span class="hljs-keyword">if</span>(! src.hasOwnProperty(name)){ <span class="hljs-keyword">continue</span>; }
            <span class="hljs-keyword">if</span>(deep &amp;&amp; type(src&#91;name]) === <span class="hljs-string">"object"</span>){
                dest&#91;name] = extend(deep, dest&#91;name] || {}, src&#91;name]);
                <span class="hljs-keyword">continue</span>;
            }
            dest&#91;name] = src&#91;name];
        }
    };
    <span class="hljs-keyword">for</span>(; i&lt;<span class="hljs-built_in">arguments</span>.length; i++){
        merge(deep, dest, <span class="hljs-built_in">arguments</span>&#91;i]);
    }
    <span class="hljs-keyword">return</span> dest;
};
</code></span></pre>


<p>jQuery等がない状況でコードを書く時や、<br />
好みの動作を行う extend 関数が欲しい時には自作のスニペットを用意しておくと捗るかもしれませんね。</p>



<h2 class="wp-block-heading">参考資料</h2>



<ul class="wp-block-list">
<li><a href="http://api.jquery.com/jQuery.extend/">jQuery.extend() | jQuery API Documentation</a></li>



<li><a href="http://underscorejs.org/">Underscore.js</a></li>
</ul>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
