资讯专栏INFORMATION COLUMN

【译】在时间属性上慎用Angular.js1.4的“angular.merge”函数

MasonEast / 960人阅读

摘要:现在让我们用来复制我们可能看到,当用的时候,对象属性是递归复制的。到目前为止,一切看起来还不错。如果深入研究的源码,我们会发现,无论是还是都调用了这个内部函数。结果如下总结将框架升级到新版本是一种冒险行为。

在时间属性上慎用Angular.js1.4的“angular.merge”函数

原文:Pay Attention to "angular.merge" in 1.4 on Date Properties

今天我将应用从Angular.js1.3.9升级到1.4的时候,发现了一些Bug。在经过一翻研究后,发现它们与时间属性及1.4中的“angular.merge”函数有关。

在官方文档中,“angular.merge”的表述如下:

复制src对象中的可枚举属性到dst对象中,以深度扩展目标对象“dst”。

同时也提到了与先前版本中的”angular.extend“的区别。

与"extend()"不同,在进行深度复制时,"merge()"支持递归复制。

让我们来看一个简单的例子,在下面的代码中,作用域内有一个源对象和一个自定义对象,接着我用”angular.extend“将自定义对象复制到源对象中。

 $scope.source = {
   name: "Shaun",
   age: 35,
   birthDate: new Date(1997, 5, 27),
   skills: {
     dotNet: {
       level: "expert",
       years: 10
     },
     javaScript: {
       level: "newbie",
       years: 2
     }
   },
   mvp: [
     2011,
     2012,
     2013,
     2014,
     2015
   ]
 };
  
 $scope.custom = {
   name: "Ziyan",
   age: 35,
   skills: {
     dotNet: {
       level: "hero", 
       years: 100,
       active: true
     },
   },
   mvp: [
     2016
   ]
 };
  
 $scope.extend = angular.extend({}, $scope.source, $scope.custom);

从结果中我们可以看到,“angular.extend”执行的是浅拷贝,像“name”,”age”和“birthDate”这些原始属性值已经合并了,但因为“skills”和”mvp”是对象和数组,”angular.extend“会复制全部值,而不是数组或对象中的成员。

现在让我们用“angular.merge”来复制:

$scope.merge = angular.merge({}, $scope.source, $scope.custom);

我们可能看到,当用“angular.merge”的时候,对象属性是递归复制的。

到目前为止,一切看起来还不错。但是有些人可能会发现,在使用“angular.merge”的时候,其中一个属性“birthDate”被设成了空对象。

如果深入研究angular.js的源码,我们会发现,无论是“angular.extend”还是“angular.merge”都调用了“baseExtend”这个内部函数。它将多个对象合并到目标对象,用一个标志参数来表明是否为深度合并。

在这个函数内部,会遍历每个可枚举属性,将值复制到目标对象。如果源属性是一个对象并且需要深度复制,Angular.js会在目标对象中创建一个空对象,并且对这个属性递归执行这个函数。

   function baseExtend(dst, objs, deep) {
      var h = dst.$$hashKey;
     
      for (var i = 0, ii = objs.length; i < ii; ++i) {
        var obj = objs[i];
        if (!isObject(obj) && !isFunction(obj)) continue;
        var keys = Object.keys(obj);
        for (var j = 0, jj = keys.length; j < jj; j++) {
          var key = keys[j];
         var src = obj[key];
    
         if (deep && isObject(src)) {
           if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
           baseExtend(dst[key], [src], true);
         } else {
           dst[key] = src;
         }
       }
     }
    
     setHashKey(dst, h);
     return dst;
   }

除了日期之外,它几乎可以处理所有情况。如果我们定义了一个日期属性,例如“birthDate”,它就会用“angular.isObject”检查这个属性是否是为对象,返回的是“true”。所以它会在目标对象中创建一个属性名为“birthDate”的空对象,并且对“birthDate”调用“baseExtend”。但是因为“birthDate”的属性为Date,并不是可枚举属性,所以这个对象不会分配到任何数据。这就是为什么结果中"birthDate"属性为空的原因。

如果我将Angular.js 中的“baseExtend”函数复制到作用域内,并将代码改成如下形式,当属性为Date时,也会执行简单的复制了。

 $scope.$baseExtend = function (dst, objs, deep) {
   for (var i = 0, ii = objs.length; i < ii; ++i) {
     var obj = objs[i];
     if (!angular.isObject(obj) && !angular.isFunction(obj)) {
      console.log("[" + obj + "] = (skip)");
       continue;
     }
     var keys = Object.keys(obj);
     for (var j = 0, jj = keys.length; j < jj; j++) {
       var key = keys[j];
       var src = obj[key];
       // perform deep copy if
       // 1. spcified by user
       // 2. source property is an object
       // 3. source property is NOT a date
       if (deep && angular.isObject(src) && !angular.isDate(src)) {
         if (!angular.isObject(dst[key])) {
           console.log("[" + key + "] = (Try copy an object to an non-object, create an empty for deep copy.)");
           dst[key] = angular.isArray(src) ? [] : {};
         }
         $scope.$baseExtend(dst[key], [src], true);
       } 
       else {
         dst[key] = src;
         
         console.log("[" + key + "] = " + src);
       }
     }
   }
   return dst;
 };
  
 $scope.sample = $scope.$baseExtend({}, [$scope.source, $scope.custom], true);

结果如下:

总结:

将框架升级到新版本是一种冒险行为。我们需要进行大量的回归测试,以确保不会出现任何问题。我在执行E2E测试时发现了这个问题。我想这是Angular.js的Bug,我已经将这个问题贴了出来。在他们确认和修改之前,在你的应用中,慎用“angular.merge”这个函数。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78526.html

相关文章

  • AngularJS核心对象angular方法全面解析(AngularJS全局API)

    摘要:总结一下的核心对象上的方法,也帮助自己学习一下平时工作中没怎么用到的方法,看能不能提高开发效率。我当前使用的版本是也是目前最新的稳定版本,不过在全局上,版本不同也没什么区别。在引入了的情况下,使用方法和几乎一样,相当于一个语法糖。 总结一下AngularJS的核心对象angular上的方法,也帮助自己学习一下平时工作中没怎么用到的方法,看能不能提高开发效率。我当前使用的Angularj...

    RdouTyping 评论0 收藏0
  • AngularJS核心对象angular方法全面解析(AngularJS全局API)

    摘要:总结一下的核心对象上的方法,也帮助自己学习一下平时工作中没怎么用到的方法,看能不能提高开发效率。我当前使用的版本是也是目前最新的稳定版本,不过在全局上,版本不同也没什么区别。在引入了的情况下,使用方法和几乎一样,相当于一个语法糖。 总结一下AngularJS的核心对象angular上的方法,也帮助自己学习一下平时工作中没怎么用到的方法,看能不能提高开发效率。我当前使用的Angularj...

    pubdreamcc 评论0 收藏0
  • 体验javascript之美第七课 理解原型链和扩展原型方法

    摘要:原型链理解第一件事你不用管其他语言,一句话,你只要记住里面的对象包含一个原型,原型是啥,就是另外一个对象。原型就相当于你家的车棚子,而你的那个自行车就是对象。万事万物皆对象有啥用一句话,扩展原型方法,给大家一到面试题,数组去重自己体会下。 概述 通过上节课的学习,大家已经会用一种json的方式定义对象了,其实这个就是传说中的单体模式,当然这个大家不用记,关于设计模式暂时不用了解。但是总...

    wslongchen 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<