jQueryのmergeとextendとjQueryプラグイン

extendといえば、"継承する"という意味だと思っておりましたが、広げる、拡張するといった意味合いの言葉のようです。

jQueryプラグインを作成する際にも使用し、意味合い的にもぴったりのextendですが、それ専用のメソッドというわけではありません。

[公式のドキュメント](http://api.jquery.com/jquery.extend/)はプラグイン作成用途ではない説明がメインで行われているため、まずはこの使い方を理解する必要があるでしょう。

# jQuery.merge

```js
jQuery.merge( Array1, Array2 )
```

マージといえば、割とおなじみの言葉だと思います。なんか混ぜ合わせる感じですが、jQueryのextendとmergeはほぼ同じものといっていいと思います。違うのは、混ぜ合わせるのが配列かオブジェクトかという点です。

## jQuery.mergeの特徴

- 配列(Array)をマージする
- 引数はn個ではない
 - 何個でもマージできるわけではなく2個
- Array1が上書きされる

## Array1が上書きされたくないときの書き方

```js
var first = [ "a", "b", "c" ];
var second = [ "d", "e", "f" ];
var mg_arr = $.merge( $.merge( [], first ), second );
```

空の配列にマージしてます。$.mergeの返り値はマージ後の配列なのでそれを変数に代入しています。

通常Array1が書き換わるため、空の配列ではない場合、マージ時の返り値を変数に代入する必要はありません。

```js
var first = [ "a", "b", "c" ];
var second = [ "d", "e", "f" ];

$.merge( first , second );
first; // 書き換わってる
```

# jQuery.extend

```js
// version 1.0～
jQuery.extend( target [, object1 ] [, objectN ] )
```

```js
// version 1.1.4～
jQuery.extend( [deep ], target, object1 [, objectN ] )
```

2種類の書き方があるんです。すでにややこしいですが、mergeと対比するextendはversion 1.1.4の書き方です。

ほぼ一緒のように見えますが、version 1.0はオブジェクトが一つでもいいところが大きな違いです。

以降は、version 1.1.4から追加されたほうのextendに関する解説です。

## jQuery.extendの特徴

- オブジェクトをマージする
- 引数はn個(**何個でも！**)
- Array1が上書きされる

## Array1が上書きされたくないときの書き方

```js
var object = $.extend({}, object1, object2);
```

mergeと大体同じですが、引数がn個なおかげで、すっきり書くことができます。

## [deep ]オプション

このオプションは、`true`を指定するか、もしくは省略するかのどちらかです。`false`を指定することはできません。

説明によると、

> If true, the merge becomes recursive (aka. deep copy).

ということです。`trueだったら、マージが再帰的になる`なるほど、わからんですね。

サンプルを見てみましょう。

```js
var object1 = {
  apple: 0,
  banana: { weight: 52, price: 100 },
  cherry: 97
};
var object2 = {
  banana: {
    price: 200
  },
  durian: 100
};
$.extend( object1, object2 );
```

結果は以下のようになりました。

```js
$.extend( object1, object2 );

Object {
  apple : 0
  banana : Object {
    price : 200
  }
  price : 200
  cherry : 97
  durian : 100
}
```

weightがなくなってしまいました。
[deep ]をtrueにすると結果は、以下のように変わります。

```js
$.extend( true, object1, object2 );

Object {
  apple : 0
  banana : Object {
    weight : 52,
    price : 200
  }
  price : 200
  cherry : 97
  durian : 100
}
```

今度は、weightが残ったままのようです。
`aka. deep copy`という説明がありましたが、深い階層も同じように処理するかどうかということです。

trueにすると、オブジェクトの中のオブジェクトも同じようにマージしてくれます。trueでない場合は、中身を無視してまるごと上書きしてしまった感じです。

# jQueryプラグインのためのextend

```js
jQuery.fn.extend( object )
```

上記と`jQuery.extend`は似ていますが、`fn`をつけるだけで全く異なるものになることに注意してください。
jQueryは、`fn`をつけることによって、prototypeを参照します。（prototypeが何なのか気になる場合は、[こちら](http://qiita.com/nmta/items/696eeab1d6b96e3bfc1a)を参考にしてみてください)

`jQuery.fn.extend`について、`$.each`を例にご説明します。

```js
$.extend({
  each : function() {}
});
// => $.each();
```

jQueryそのものをパワーアップさせるのが、`$.extend`です。
ユーティリティ関数と呼ばれています。

```html
<div class="btn"></div>
<div class="btn"></div>
<div class="btn"></div>
```

```js
$.fn.extend({
  each : function() {}
});
// => $(".btn").each();
```

jQueryでお馴染みの書き方ができるようになるのが`$.fn.extend`です。JavaScript的にも頭にtargetがくる書き方はしっくりきます。

他にも以下のように書くこともできます。

```js
$.fn.each = function() {}
});
```

```js
$.extend($.fn, {
    each : function() {}
});
```

これらはすべて、jQueryのprototypeを拡張する方法です。

`each`は元々jQueryに存在するメソッドですが、オリジナルのメソッドを定義することもできます。

```js
$.fn.extend({
  open : function() {},
  close : function() {}
});
```

一般的なjQueryプラグインもこのように拡張されています。

# jQueryプラグインで便利なextendの使い方

jQueryプラグインで、ユーザーが自由に設定を変更できるオプションを作成する方法を紹介します。
jQueryプラグインには、初期値としてあらかじめ`defaults`というオブジェクトを定義します。

```js
var defaults = {
  width: 100,
  height: 100.
  maxlength: 10,
  message : {
    ok : "good",
    ng : "sorry"
  }
}
```

この`defaults`に定義するのは、プラグインの中で使用する変数です。

```js
$("#sample").hogePlugin({
  width: 200,
  message : {
    ng : "bad"
  }
});
```

このようにユーザーは、オプションを指定し、`defaults`の値を更新することができます。実行時の引数に渡すというやり方がスマートです。

更にこのオプションのいいところは、指定したものだけを上書き、指定しなかったものは、`defaults`の値を使用するところです。
これにより、「デフォルト値の場合は省略可」を実現できます。

もちろんこの際、オプションの値で`defaults`を更新するのに使用するのが**extend**です。

## ダメな書き方

```js
$.extend(defaults, options);
```

なぜダメかわかるでしょうか。
上でも説明しましたが、この例のようなオブジェクトの場合、"再帰的"にしなければmessage.okが消えてしまいます。
ただし、再帰的にする必要がなければ特に問題はありません。

## 普通な書き方

```js
$.extend(true, defaults, options);
```

これで再帰的に処理されます。
しかし、個人的にはこれもまだ微妙です。これでは今後使用するのが`defaults`ということになります。`defaults`はあくまで初期値であり、設定時に使用するのは`options`を使用した方が綺麗でしょう。

## マシな書き方

```js
options = $.extend(true, defaults, options);
```

これで`options`を使用できるようになりましたが、まだ`defaults`が書き換わってしまっている点が微妙です。初期値が必要になった場合など困ってしまいます。

## オススメの書き方

```js
options = $.extend(true, {}, defaults, options);
```

これで`defaults`を保持しつつ、見事`defaults`と`options`をマージすることができました。