var typeOf = require('./typeof'), slice = Array.prototype.slice; module.exports = { clone: deepClone, cloneShallow: clone, extend: deepExtend, extendShallow: extend, update: deepUpdate, updateShallow: update, merge: deepMerge, mergeShallow: merge }; function clone(val) { switch(typeOf(val)) { case 'object': var args = slice.call(arguments); args.unshift({}); return extend.apply(null, args); case 'array': return [].concat(val); case 'date': return new Date(val.getTime()); case 'regexp': return new RegExp(val); default: return val; } } function deepClone(val) { switch(typeOf(val)) { case 'object': var args = slice.call(arguments); args.unshift({}); return deepExtend.apply(null, args); case 'array': return val.map(function(v) { return deepClone(v); }); default: return clone(val); } } function extend(a, b /*, [b2..n] */) { slice.call(arguments, 1).forEach(function(b) { Object.keys(b).forEach(function(p) { a[p] = b[p]; }); }); return a; } function deepExtend(a, b /*, [b2..n] */) { slice.call(arguments, 1).forEach(function(b) { Object.keys(b).forEach(function(p) { if(typeOf(b[p]) === 'object' && typeOf(a[p]) === 'object') deepExtend(a[p], b[p]); else a[p] = deepClone(b[p]); }); }); return a; } function update(a, b /*, [b2..n] */) { slice.call(arguments, 1).forEach(function(b) { Object.keys(b).forEach(function(p) { if(a.hasOwnProperty(p)) a[p] = b[p]; }); }); return a; } function deepUpdate(a, b /*, [b2..n] */) { slice.call(arguments, 1).forEach(function(b) { var ap, bp, ta, tb; Object.keys(b).forEach(function(p) { if(a.hasOwnProperty(p)) { ap = a[p]; bp = b[p]; ta = typeOf(ap); tb = typeOf(bp); if(tb === 'object' && ta === 'object') deepUpdate(ap, bp); else if(tb === 'array' && ta === 'array') { ap.length = 0; ap.push.apply(ap, bp.map(function(v) { return deepClone(v); })); } else a[p] = deepClone(bp); } }); }); return a; } function merge(a, b /*, [b2..n] */) { slice.call(arguments, 1).forEach(function(b) { Object.keys(b).forEach(function(p) { if(!a.hasOwnProperty(p)) a[p] = b[p]; }); }); return a; } function deepMerge(a, b /*, [b2..n] */) { slice.call(arguments, 1).forEach(function(b) { var ap, bp, ta, tb; Object.keys(b).forEach(function(p) { ap = a[p]; bp = b[p]; ta = typeOf(ap); tb = typeOf(bp); if(tb === 'object' && ta === 'object') deepMerge(ap, bp); else if(!a.hasOwnProperty(p)) a[p] = deepClone(bp); }); }); return a; }