object/merge.jsjavascript
/**
 * 判断值是否可递归合并。
 * @private
 */
function isMergeable(value) {
  return value !== null && typeof value === 'object' && !ArrayBuffer.isView(value) && !(value instanceof Date) && !(value instanceof RegExp)
}

/**
 * 递归合并两个值。
 * @private
 */
function mergeValues(target, source) {
  if (!isMergeable(source)) return source
  const output = Array.isArray(source) ? (Array.isArray(target) ? target.slice() : []) : (isMergeable(target) && !Array.isArray(target) ? { ...target } : {})
  Object.entries(source).forEach(([key, value]) => {
    output[key] = isMergeable(value) ? mergeValues(output[key], value) : value
  })
  return output
}

/**
 * 深度合并多个普通对象,不修改任何输入对象。
 * @function merge
 * @memberof module:object
 * @param {...Object} objects 要合并的对象
 * @returns {Object} 合并后的新对象
 * @throws {TypeError} 参数不是普通对象时抛出
 */
function merge(...objects) {
  if (objects.some(value => !isMergeable(value) || Array.isArray(value))) throw new TypeError('all arguments must be plain objects')
  return objects.reduce((result, object) => mergeValues(result, object), {})
}

export default merge