jQueryの$.extend()を生JavaScriptで実装する脱jQuery

jQueryプラグインを作るときによく使う $.extend() 関数を生JSで実装してみました。Object.assign() を使った方法もありますがまだ全てのブラウザで使えるわけではなかったので、IE8+から使えるようにしてあります。

$.extend()


var extend = function() {
  var i = 1,
      key,
      length = arguments.length,
      // 引数がなければ空のオブジェクトを返す
      target = arguments[0] || {},
      isDeep = false;
  
  // 第1引数がtrueだったときディープコピー
  if (target === true) {
    ++i;
    target = arguments[1] || {};
    isDeep = true;
  }
  
  // 引数の数だけループ
  // 第1引数は除く(ディープコピーの場合は第2引数も)
  for (; i < length; ++i) {
    for (key in arguments[i]) {
      if (arguments[i].hasOwnProperty(key)) {
        // ディープコピーの場合は再帰呼び出し
        if (isDeep && Object.prototype.toString.call(arguments[i][key]) === '[object Object]') {
          target[key] = extend(target[key], arguments[i][key]);
        } else {
          target[key] = arguments[i][key];
        }
      }
    }
  }
  
  return target;
};

使い方


var object1 = {
  a: 0,
  b: {
    aa: 3,
    bb: 10
  },
  c: 6
};
var object2 = {
  a: 4,
  b: {
    bb: 7
  },
  d: 2
};

var result = extend({}, object1, object2);

{
  a: 4,
  b: {
    bb: 7
  },
  c: 6,
  d: 2
}

1階層目のプロパティが継承されているのがわかります。しかし、2階層目の object1.b.aa が消えてしまっています。多階層に対応させるときは、第1引数true を渡せばディープコピーをすることができます。


var result = extend(true, {}, object1, object2);

{
  a: 4,
  b: {
    aa: 3,
    bb: 7
  },
  c: 6,
  d: 2
}