code: function mergeDefaults(src, levels = undefined, isImmutable = false, deepCloneSrc = false) {
      let dst = this;
      levels = levels || Number.MAX_SAFE_INTEGER;
      let isCopy = !isImmutable;
      let dstValue;
      let newValue;
  
      if (isObjectLike(dst) && isObjectLike(src)) {
          const keys = Object.keys(src);
          const iMax = keys.length;
          for (let i = 0; i < iMax; i++) {
              const key = keys[i];
              const value = src[key];
  
              if (value !== UNDEFINED) {
                  newValue = dstValue = isObjectLike(dst) && dst.hasOwnProperty(key) ? dst[key] : UNDEFINED;
  
                  if (!isValid(dstValue)) {
                      newValue = value;
                  } else if (levels > 1 && isObjectLike(dstValue) && !isArray(dstValue)) {
                      // cannot deep merge arrays, would just mess up the values
                      newValue = mergeDefaults.call(dstValue, value, levels - 1, isImmutable, deepCloneSrc);
                  }
  
                  if (newValue !== dstValue) {
                      if (!isCopy) {
                          dst = cloneArrayObject.call(dst);
                          isCopy = true;
                      }
  
                      if (deepCloneSrc && isObjectLike(newValue)) {
                          newValue = deepClone(newValue);
                      }
                      dst[key] = newValue;
                  }
              }
          }
      }
      return dst;
  }
docs: defaultMerge properties
  @this                destination object to merge defaults into
  @param src           source of defaults
  @param levels        number of levels deep to merge defaults, all levels if not specified.
  @param isImmutable   if true then make a copy if changing
  @param deepCloneSrc  make a deep copy of src values if copying to dst
  @return {*}          defaults merged (copy if not mutable or original if mutable)