function merge(/* obj1, obj2, obj3, ... */) {
  const {caseless} = isContextDefined(this) && this || {};
  const result = {};
  const assignValue = (val, key) => {
    const targetKey = caseless && findKey(result, key) || key;
    if (isPlainObject(result[targetKey]) && isPlainObject(val)) {
      result[targetKey] = merge(result[targetKey], val);
    } else if (isPlainObject(val)) {
      result[targetKey] = merge({}, val);
    } else if (isArray(val)) {
      result[targetKey] = val.slice();
    } else {
      result[targetKey] = val;
    }
  };

  for (let i = 0, l = arguments.length; i < l; i++) {
    arguments[i] && forEach(arguments[i], assignValue);
  }
  return result;
}
Accepts varargs expecting each argument to be an object, then
immutably merges the properties of each object and returns result.

When multiple objects contain the same key the later object in
the arguments list will take precedence.

Example:

```js
var result = merge({foo: 123}, {foo: 456});
console.log(result.foo); // outputs 456
```

@param {Object} obj1 Object to merge

@returns {Object} Result of all merge properties