Objectのmerge

Objectを再帰的にマージしたい。

var _ = require('underscore')._;
var a = { hoge: { key1: 'val1' } };
var b = { hoge: { key2: 'val2' } };

console.log(_.extend(a, b));
// こうなってほしいけど
// { hoge: { key1: 'val1', key2: 'val2' } }
//
// 実際はこう
// { hoge: { key2: 'val2' } }

jQuery.extendでディープコピーとすればいけるっぽい。

$.extend(true, {}, a, b);

でもnodeでそれだけのためにjQuery使いたくないのでとりあえずこうした。
破壊的だし色々いまいちだけど。

function merge() {
  return [].reduce.call(arguments, function _merge(a, b) {
    Object.keys(b).forEach(function(key) {
      a[key] = (isObject(a[key]) && isObject(b[key]))
        ? a[key] = _merge(a[key], b[key])
        : a[key] = b[key];
    });
    return a;
  });
}

function isObject(obj) {
  return obj instanceof Object && Object.getPrototypeOf(obj) === Object.prototype;
}

var a = { hoge: { key1: 'val1' } };
var b = { hoge: { key2: 'val2' } };
console.log(merge(a, b));
// => { hoge: { key1: 'val1', key2: 'val2' } }