Module: bff/extend


(require("bff/extend"))(target, source [, onConflict] [, defaultOnConflict])

A function that extends a target object with the properties of a source object, with options for describing property collision behavior. Note that the target object is mutated and returned, i.e. no new object gets created by invoking this function.

The function comes with a set of named built-in conflict-solving functions:

  • crash: Throws an error when a property conflict occurs. This is the default solver function.
  • useTarget: Uses the target's property, i.e. leaves the target property unchanged.
  • useSource: Uses the source's property, i.e. overwrites the target property with the source property.
  • merge: Tries to merge the values in an intuitive way.
    • Objects are merged recursively.
    • Arrays are concatenated.
    • Functions are combined, so that the target's function is first called, then the source's. Both functions are passed the same arguments.
    • Numbers and strings added using the + operator.
    • Boolean values are or:ed using the || operator (i.e. Boolean addition).
    • If the source and target types are not the same, use the source value.
      The caller also has the option to specify custom solver functions.

Examples

extend(
  { a: { b: 'b', c: 'c' } },
  { a: { c: 'c', d: 'd' } },
  'useSource');
// Returns { a: { c: 'c', d: 'd' } }

As can be seen in above, the 'useSource' conflict solver is not recursive, it simply overwrites any property it encounters. This is how e.g. jQuery.extend and _.assign behaves.

extend(
  { a: { b: 'b', c: 'c' } },
  { a: { c: 'c', d: 'd' } },
  'merge');
// Returns { a: { b: 'b', c: 'c', d: 'd' } }

Here we see that the 'merge' solver works recursively.

extend(
  { a: { b: 'b' }, num: 1 },
  { a: { c: 'c' }, num: 2 },
  { object: 'merge' }, 'useSource');
// Returns { a: { b: 'b', c: 'c' }, num: 2 }

The above example uses the 'merge' solver on objects and the 'useSource' solver on all other property types. This produces a recursive behavior over objects, which is quite often desired. This is how e.g. _.merge behaves

extend(
  { a: { b: 'b' }, num: 1 },
  { a: { c: 'c' }, num: 2, newProp: 3 },
  function (target, source, prop) { target[prop] = 42; });
// Returns { a: 42, num: 42, newProp: 3 }

Above we see a (fairly useless) custom conflict solver function.

Parameters:
Name Type Argument Description
target Object

The object that will be extende with new properties.

source Object

The object that provides the new properties.

onConflict string | module:bff/extend~conflictSolver | Object <optional>

Specifies how to handle cases where a property exists both on the target and on the source.

  • a string argument will be used to identify one of the built in solver functions. Valid values are 'useTarget', 'useSouce', 'crash' and 'merge'.
  • a function argument will be used as-is as a solver for all conflicts.
  • an Object argument should have keys that correspond to value types, i.e. 'object', 'array', 'function', 'string', 'number', 'boolean', 'null' or 'undefined'. The object values can be either strings or functions, which will be used as solver functions for the corresponding key value types.
defaultOnConflict string | module:bff/extend~conflictSolver <optional>

Specifies a default solver, in the same manner as the onConflict argument. Can only be used if onConflict is an object.

Source:
Returns:

The extended object

Type
Object

Type Definitions


conflictSolver(target, source, prop, onConflict, defaultOnConflict)

Parameters:
Name Type Description
target Object
source Object
prop string

The name of the conflicting property.

onConflict string | module:bff/extend~conflictSolver | Object

The same onConflict argumet passed to the extend() call.

defaultOnConflict string | module:bff/extend~conflictSolver

The same defaultOnConfluct argumet passed to the extend() call.

Source: