在JavaScript中比较对象的最佳方式是什么?

示例:

var user1 = {name : "nerd", org: "dev"};
var user2 = {name : "nerd", org: "dev"};
var eq = user1 == user2;
alert(eq); // gives false

我知道有two objects are equal if they refer to the exact same object个,但有没有办法判断它们是否具有相同的属性值?

下面的方法对我有效,但这是唯一的可能性吗?

var eq = Object.toJSON(user1) == Object.toJSON(user2);
alert(eq); // gives true

推荐答案

不幸的是,没有完美的方法,除非您递归地使用_proto_并访问所有不可枚举的属性,但这只适用于Firefox.

所以我能做的最多的就是猜测使用场景.


1)快速、有限.

当您有简单的JSON样式的对象,但其中没有方法和DOM node 时,此功能会起作用:

 JSON.stringify(obj1) === JSON.stringify(obj2) 

属性的顺序很重要,因此对于以下对象,此方法将返回false:

 x = {a: 1, b: 2};
 y = {b: 2, a: 1};

2) 慢而且更通用.

在不深入原型的情况下比较对象,然后递归比较属性的投影,还比较构造函数.

这几乎是正确的算法:

function deepCompare () {
  var i, l, leftChain, rightChain;

  function compare2Objects (x, y) {
    var p;

    // remember that NaN === NaN returns false
    // and isNaN(undefined) returns true
    if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
         return true;
    }

    // Compare primitives and functions.     
    // Check if both arguments link to the same object.
    // Especially useful on the step where we compare prototypes
    if (x === y) {
        return true;
    }

    // Works in case when functions are created in constructor.
    // Comparing dates is a common scenario. Another built-ins?
    // We can even handle functions passed across iframes
    if ((typeof x === 'function' && typeof y === 'function') ||
       (x instanceof Date && y instanceof Date) ||
       (x instanceof RegExp && y instanceof RegExp) ||
       (x instanceof String && y instanceof String) ||
       (x instanceof Number && y instanceof Number)) {
        return x.toString() === y.toString();
    }

    // At last checking prototypes as good as we can
    if (!(x instanceof Object && y instanceof Object)) {
        return false;
    }

    if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
        return false;
    }

    if (x.constructor !== y.constructor) {
        return false;
    }

    if (x.prototype !== y.prototype) {
        return false;
    }

    // Check for infinitive linking loops
    if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
         return false;
    }

    // Quick checking of one object being a subset of another.
    // todo: cache the structure of arguments[0] for performance
    for (p in y) {
        if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
            return false;
        }
        else if (typeof y[p] !== typeof x[p]) {
            return false;
        }
    }

    for (p in x) {
        if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
            return false;
        }
        else if (typeof y[p] !== typeof x[p]) {
            return false;
        }

        switch (typeof (x[p])) {
            case 'object':
            case 'function':

                leftChain.push(x);
                rightChain.push(y);

                if (!compare2Objects (x[p], y[p])) {
                    return false;
                }

                leftChain.pop();
                rightChain.pop();
                break;

            default:
                if (x[p] !== y[p]) {
                    return false;
                }
                break;
        }
    }

    return true;
  }

  if (arguments.length < 1) {
    return true; //Die silently? Don't know how to handle such case, please help...
    // throw "Need two or more arguments to compare";
  }

  for (i = 1, l = arguments.length; i < l; i++) {

      leftChain = []; //Todo: this can be cached
      rightChain = [];

      if (!compare2Objects(arguments[0], arguments[i])) {
          return false;
      }
  }

  return true;
}

已知问题(嗯,它们的优先级很低,可能你永远不会注意到):

  • 原型 struct 不同但投影相同的对象
  • 函数可以具有相同的文本,但引用不同的闭包

通过测试的Tests:人来自100人.

Javascript相关问答推荐

使用CDO时如何将Vue组件存储在html之外?

如何在JavaScript中通过一次单击即可举办多个活动

为什么在获取回调内设置状态(不会)会导致无限循环?

创建1:1比例元素,以另一个元素为中心

在JavaScript中对大型级联数组进行切片的最有效方法?

对象和数字减法会抵消浏览器js中的数字

如何在表格上拥有水平滚动条,在正文页面上拥有垂直滚动条,同时还对html表格的标题使用位置粘性?

调用removeEvents不起作用

未捕获错误:在注销后重定向到/login页面时找不到匹配的路由

扫描qr code后出错whatter—web.js

无法访问Vue 3深度监视器中对象数组的特定对象值'

使用Promise.All并发解决时,每个promise 的线性时间增加?

为什么我的getAsFile()方法返回空?

如何将未排序的元素追加到数组的末尾?

在开发期间,Web浏览器如何运行&qot;.jsx&qot;文件?

将基元传递给THEN处理程序

Reaction即使在重新呈现后也会在方法内部保留局部值

如何在FiRestore中的事务中使用getCountFromServer

在JavaScript中将Base64转换为JSON

如何使用puppeteer操作所有选项