【问题标题】:Equivalent of angular.equals in angular2angular2 中 angular.equals 的等价物
【发布时间】:2017-03-28 14:47:44
【问题描述】:

我正在将 angular 1 项目迁移到 angular 2 。在 angular 1 项目中,我使用 angular.equals 进行对象比较 angular.equals($ctrl.obj1, $ctrl.newObj); ,我在网上搜索了 angular 2 中的等效方法,但找不到任何匹配的结果。

【问题讨论】:

标签: angularjs object angular typescript


【解决方案1】:

@Günter 是的,你是对的,在 angular2 中没有等价物。在搜索更多内容时,我发现第三方库 lodash 将与 angular.equals 完成相同的工作,并且语法与 angular one 相同,这个库解决了我的问题

lodash 文档中的代码示例

var object = { 'a': 1 };
var other = { 'a': 1 };
 
_.isEqual(object, other);
// => true
 
object === other;
// => false

【讨论】:

    【解决方案2】:

    我重写了 Ariels 的答案(谢谢!),使其对 TSLINT 友好。您也可以通过使用 else if 来保存一些 continue,但我认为这更清楚。也许其他人也需要它:

    export function deepEquals(x, y) {
      if (x === y) {
        return true; // if both x and y are null or undefined and exactly the same
      } else if (!(x instanceof Object) || !(y instanceof Object)) {
        return false; // if they are not strictly equal, they both need to be Objects
      } else if (x.constructor !== y.constructor) {
        // they must have the exact same prototype chain, the closest we can do is
        // test their constructor.
        return false;
      } else {
        for (const p in x) {
          if (!x.hasOwnProperty(p)) {
            continue; // other properties were tested using x.constructor === y.constructor
          }
          if (!y.hasOwnProperty(p)) {
            return false; // allows to compare x[ p ] and y[ p ] when set to undefined
          }
          if (x[p] === y[p]) {
            continue; // if they have the same strict value or identity then they are equal
          }
          if (typeof (x[p]) !== 'object') {
            return false; // Numbers, Strings, Functions, Booleans must be strictly equal
          }
          if (!deepEquals(x[p], y[p])) {
            return false;
          }
        }
        for (const p in y) {
          if (y.hasOwnProperty(p) && !x.hasOwnProperty(p)) {
            return false;
          }
        }
        return true;
      }
    }
    

    【讨论】:

    • 大多数 IDE 应该有一个“保存时自动格式化”选项,它会自动更改代码以匹配您的 linting 设置。在 VSCode 上它是 "editor.formatOnSave": true,与 prettier 插件一起使用(可能还有 tslint/ eslint
    • 当我尝试使用这个例程时,当两个对象有一个不是同一日期的 JavaScript Date 类型的成员时,它返回了一个误报。期望应该使用getTime() 比较两个 JS 日期
    • 这是 90% 的路,但它不处理引用循环。例如,如果foo.ref = foobar.ref = bar 这个方法将陷入无限循环,因为它们都具有{ ref: {...} } 的相同结构但引用不同的实例。
    【解决方案3】:

    您可以使用 JSON.stringify 并比较两个字符串,而不是编写一个函数来遍历对象?

    例子:

    var obj1 = {
      title: 'title1',
      tags: []
    }
    
    var obj2 = {
      title: 'title1',
      tags: ['r']
    }
    
    
    console.log(JSON.stringify(obj1));
    console.log(JSON.stringify(obj2));
    
    
    console.log(JSON.stringify(obj1) === JSON.stringify(obj2));
    

    【讨论】:

    • 这适用于大多数情况,但对于语义相同的情况可能会失败。例如,从您的示例中重新排序成员 jsfiddle.net/9d8gjy9e
    • 这对我有用,因为我只是比较简单的对象
    • 因为成员的顺序很重要,这样比较是不行的
    • 如果您不介意它可能会失败的边缘情况,这是一个很好的快速解决方案。另外,JSON.stringify fails due to circular references.
    • 不应该以任何理由依赖它(除了可能用于非常旧的 IE 的 polyfill,包括出于性能原因的失败时完整属性/值比较)
    【解决方案4】:

    在 Angular 2 中,您应该为此使用纯 JavaScript/TypeScript,以便您可以将此方法添加到某些服务中

    private static equals(x, y) {
        if (x === y)
            return true;
        // if both x and y are null or undefined and exactly the same
        if (!(x instanceof Object) || !(y instanceof Object))
            return false;
        // if they are not strictly equal, they both need to be Objects
        if (x.constructor !== y.constructor)
            return false;
        // they must have the exact same prototype chain, the closest we can do is
        // test there constructor.
    
        let p;
        for (p in x) {
            if (!x.hasOwnProperty(p))
                continue;
            // other properties were tested using x.constructor === y.constructor
            if (!y.hasOwnProperty(p))
                return false;
            // allows to compare x[ p ] and y[ p ] when set to undefined
            if (x[p] === y[p])
                continue;
            // if they have the same strict value or identity then they are equal
            if (typeof (x[p]) !== "object")
                return false;
            // Numbers, Strings, Functions, Booleans must be strictly equal
            if (!RXBox.equals(x[p], y[p]))
                return false;
        }
        for (p in y) {
            if (y.hasOwnProperty(p) && !x.hasOwnProperty(p))
                return false;
        }
        return true;
    }
    

    【讨论】:

    • RXBox 是什么??
    • medium.com/@ariel.henryson/… RXBox -> 这是我编写的一个库,用于处理 Angular 应用程序内部的存储,这里的函数是库的一部分。
    • 澄清一下,RXBox.equals是这个方法的限定名;它是递归的。
    【解决方案5】:
    a = { name: 'me' }
    b = { name: 'me' }
    a == b // false
    a === b // false
    JSON.stringify(a) == JSON.stringify(b) // true
    JSON.stringify(a) === JSON.stringify(b) // true
    

    【讨论】:

    • 这对于以不同顺序定义属性的对象来说会失败。见his demo here
    • 物业订单不保证。对象本质上是哈希表,不应该保证顺序。
    【解决方案6】:

    您可以从 angularjs 复制原始源代码以获取 angular.equals 函数。用法:equals(obj1, obj2);

    var toString = Object.prototype.toString;
    
    function isDefined(value) {return typeof value !== 'undefined';}
    function isFunction(value) {return typeof value === 'function';}
    function createMap() {
      return Object.create(null);
    }
    function isWindow(obj) {
      return obj && obj.window === obj;
    }
    function isScope(obj) {
      return obj && obj.$evalAsync && obj.$watch;
    }
    function isRegExp(value) {
      return toString.call(value) === '[object RegExp]';
    }
    function simpleCompare(a, b) { return a === b || (a !== a && b !== b); }
    function isDate(value) {
      return toString.call(value) === '[object Date]';
    }
    function isArray(arr) {
      return Array.isArray(arr) || arr instanceof Array;
    }
    function equals(o1, o2) {
      if (o1 === o2) return true;
      if (o1 === null || o2 === null) return false;
      // eslint-disable-next-line no-self-compare
      if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
      var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
      if (t1 === t2 && t1 === 'object') {
        if (isArray(o1)) {
          if (!isArray(o2)) return false;
          if ((length = o1.length) === o2.length) {
            for (key = 0; key < length; key++) {
              if (!equals(o1[key], o2[key])) return false;
            }
            return true;
          }
        } else if (isDate(o1)) {
          if (!isDate(o2)) return false;
          return simpleCompare(o1.getTime(), o2.getTime());
        } else if (isRegExp(o1)) {
          if (!isRegExp(o2)) return false;
          return o1.toString() === o2.toString();
        } else {
          if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
            isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
          keySet = createMap();
          for (key in o1) {
            if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
            if (!equals(o1[key], o2[key])) return false;
            keySet[key] = true;
          }
          for (key in o2) {
            if (!(key in keySet) &&
                key.charAt(0) !== '$' &&
                isDefined(o2[key]) &&
                !isFunction(o2[key])) return false;
          }
          return true;
        }
      }
      return false;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-31
      • 2016-08-13
      • 2019-11-03
      • 1970-01-01
      • 2017-06-21
      • 2020-10-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多