【问题标题】:angularjs - extend recursiveangularjs - 扩展递归
【发布时间】:2016-04-14 00:08:16
【问题描述】:

我想扩展一些递归属性(又名深拷贝)。 就像 jQuery 一样。我不包括 jquery 仅 b/c 的一件事。

jQuery.extend( true, target, object1 )

你知道用简单的 javascript 或 angularjs 有什么优雅的方法吗?

更新 请看一下并尝试完成相同的结果 http://plnkr.co/edit/GHabYbyhsqtfBPtplksO?p=preview

我确实查看了 .copy() 但“属性(对象)被删除”

【问题讨论】:

  • 但是您可以简单地从 jQuery 的源代码中复制 $.extend 吗?它是not that hard to find,非常独立。

标签: angularjs


【解决方案1】:

这是一个基于 angular.extend 函数的 extendDeep 函数。如果你把它添加到你的 $scope 中,你就可以调用

$scope.meta = $scope.extendDeep(ajaxResponse1.myMeta, ajaxResponse2.defaultMeta);

并获得您正在寻找的答案。

$scope.extendDeep = function extendDeep(dst) {
  angular.forEach(arguments, function(obj) {
    if (obj !== dst) {
      angular.forEach(obj, function(value, key) {
        if (dst[key] && dst[key].constructor && dst[key].constructor === Object) {
          extendDeep(dst[key], value);
        } else {
          dst[key] = value;
        }     
      });   
    }
  });
  return dst;
};

注意:此函数具有将值从后面的参数复制到前面的参数的副作用。对于此副作用的简单修复,您可以将dst[key] = value 更改为dst[key] = angular.copy(value)

【讨论】:

  • 这也是一个很好的解决方案,角度团队已经做了类似第一个参数 boolen(如 jquery)的事情
  • 同意。我也想,只是想演示一种使用 Angular 方法的简单方法。
  • 我认为 if (dst[key]) 实际上应该是 if (dst[key] && dst[key].constructor && dst[key].constructor === Object) - 否则它似乎无法正常工作
  • 这是更好的答案,因为它支持多个参数,但请您在@BennettMcElwee 的评论中加入修复?
  • 检查dst[key].constructor === Object的目的是什么?一个简单的 if (dst[key] && angular.isObject(dst[key])) 工作吗?
【解决方案2】:

这里的所有答案都适用于 Angular 1.4 之前的版本

从 Angular 1.4 开始,您可以使用 angular.merge 来做到这一点:

与extend() 不同,merge() 递归地下降到源对象的对象属性中,执行深度复制

https://docs.angularjs.org/api/ng/function/angular.merge

【讨论】:

【解决方案3】:
function deepExtend(destination, source) {
  for (var property in source) {
    if (source[property] && source[property].constructor &&
     source[property].constructor === Object) {
      destination[property] = destination[property] || {};
      arguments.callee(destination[property], source[property]);
    } else {
      destination[property] = source[property];
    }
  }
  return destination;
}

Plunker

源:https://gist.github.com/gregdangelo/2343158

【讨论】:

【解决方案4】:

以 Ryan 的代码为基础,您可以缩短对象检查,并且您也不应该扩展函数,以免覆盖对象指针。

var extendDeep = function extendDeep(dst) {
    angular.forEach(arguments, function(obj) {
        if (obj !== dst) {
            angular.forEach(obj, function(value, key) {
                if (dst[key] && angular.isObject(dst[key])) {
                    extendDeep(dst[key], value);
                } else if(!angular.isFunction(dst[key])) {
                    dst[key] = value;
                }
            });
        }
    });
    return dst;
};

【讨论】:

    【解决方案5】:

    与 Ryan 相同的解决方案,但支持数组合并

    function extendDeep(dst) {
          angular.forEach(arguments, function (obj) {
              if (obj !== dst) {
                angular.forEach(obj, function (value, key) {
                    if (dst[key] && dst[key].constructor && dst[key].constructor === Object) {
                      extendDeep(dst[key], value);
                    } else if (dst[key] && dst[key].constructor && dst[key].constructor === Array) {
                      dst[key].concat(value);
                    } else if(!angular.isFunction(dst[key])) {
                      dst[key] = value;
                    }
                  }
                );
              }
            }
          );
          return dst;
        }
    

    【讨论】:

      【解决方案6】:

      Angular 有一个复制方法:

      angular.copy

      【讨论】:

      • 此解决方案删除目标的内容。 angular.copy 的使用原因与 angular.extend 不同
      • 绝对不是这个问题的正确答案,但是......这个答案帮助我为我的特殊情况指明了正确的方向。 :)
      • 我认为 OP 的意思是 angular.extend(myDeepCopy, angular.copy(originalObject))