code: function deepCopy(obj) {
    var cache = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  
    // just return if obj is immutable value
    if (obj === null || (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) !== 'object') {
      return obj;
    }
  
    // if obj is hit, it is in circular structure
    var hit = find(cache, function (c) {
      return c.original === obj;
    });
    if (hit) {
      return hit.copy;
    }
  
    var copy = Array.isArray(obj) ? [] : {};
    // put the copy into cache at first
    // because we want to refer it in recursive deepCopy
    cache.push({
      original: obj,
      copy: copy
    });
  
    Object.keys(obj).forEach(function (key) {
      if (avalon.msie < 9 && /^\$\w+$/.test(key)) return;
      copy[key] = deepCopy(obj[key], cache);
    });
  
    return copy;
  }
docs: Deep copy the given object considering circular structure.
  This function caches all nested objects and its copies.
  If it detects circular structure, use cached copy to avoid infinite loop.
  
  @param {*} obj
  @param {Array<Object>} cache
  @return {*}