JavaScript中的对象比较[重复]

本文翻译自:Object comparison in JavaScript [duplicate]

This question already has answers here : 这个问题已经在这里有了答案
Closed 3 years ago . 3年前关闭。

What is the best way to compare objects in JavaScript? 在JavaScript中比较对象的最佳方法是什么?

Example: 例:

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

I know that two objects are equal if they refer to the exact same object , but is there a way to check if they have the same attributes' values? 我知道两个对象如果引用完全相同的对象则相等 ,但是有没有办法检查它们是否具有相同的属性值?

The following way works for me, but is it the only possibility? 以下方法对我有用,但这是唯一的可能性吗?

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

#1楼

参考:https://stackoom.com/question/4U3G/JavaScript中的对象比较-重复


#2楼

Certainly not the only way - you could prototype a method (against Object here but I certainly wouldn't suggest using Object for live code) to replicate C#/Java style comparison methods. 当然不是唯一的方法-您可以对方法进行原型设计(针对Object,但我当然不建议将Object用于实时代码)来复制C#/ Java样式比较方法。

Edit, since a general example seems to be expected: 编辑,因为似乎有一个一般的例子:

Object.prototype.equals = function(x)
{
    for(p in this)
    {
        switch(typeof(this[p]))
        {
            case 'object':
                if (!this[p].equals(x[p])) { return false }; break;
            case 'function':
                if (typeof(x[p])=='undefined' || (p != 'equals' && this[p].toString() != x[p].toString())) { return false; }; break;
            default:
                if (this[p] != x[p]) { return false; }
        }
    }

    for(p in x)
    {
        if(typeof(this[p])=='undefined') {return false;}
    }

    return true;
}

Note that testing methods with toString() is absolutely not good enough but a method which would be acceptable is very hard because of the problem of whitespace having meaning or not, never mind synonym methods and methods producing the same result with different implementations. 请注意,使用toString()进行测试的方法绝对不够好,但是由于空白是否有意义,问题是很难接受的,不要说同义词方法和使用不同实现产生相同结果的方法。 And the problems of prototyping against Object in general. 以及一般针对对象的原型问题。


#3楼

如果要显式检查方法,则可以使用method.toSource()或method.toString()方法。


#4楼

Unfortunately there is no perfect way, unless you use _proto_ recursively and access all non-enumerable properties, but this works in Firefox only. 不幸的是,没有完美的方法,除非您递归使用_proto_并访问所有不可枚举的属性,但这仅在Firefox中有效。

So the best I can do is to guess usage scenarios. 因此,我能做的最好是猜测使用情况。


1) Fast and limited. 1)快速且有限。

Works when you have simple JSON-style objects without methods and DOM nodes inside: 当您具有简单的JSON样式的对象,而内部没有方法和DOM节点时,则可以使用:

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

The ORDER of the properties IS IMPORTANT, so this method will return false for following objects: 属性的ORDER重要,因此对于以下对象,此方法将返回false:

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

2) Slow and more generic. 2)速度较慢,通用性更高。

Compares objects without digging into prototypes, then compares properties' projections recursively, and also compares constructors. 在不深入研究原型的情况下比较对象,然后递归比较属性的投影,还比较构造函数。

This is almost correct algorithm: 这几乎是正确的算法:

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;
}

Known issues (well, they have very low priority, probably you'll never notice them): 已知问题(嗯,它们的优先级很低,可能您永远不会注意到它们):

  • objects with different prototype structure but same projection 具有不同原型结构但投影相同的对象
  • functions may have identical text but refer to different closures 函数可能具有相同的文本,但是引用了不同的闭包

Tests: passes tests are from How to determine equality for two JavaScript objects? 测试:通过测试来自于如何确定两个JavaScript对象的相等性? .


#5楼

If you work without the JSON library, maybe this will help you out: 如果您不使用JSON库,则可能会为您提供帮助:

Object.prototype.equals = function(b) {
    var a = this;
    for(i in a) {
        if(typeof b[i] == 'undefined') {
            return false;
        }
        if(typeof b[i] == 'object') {
            if(!b[i].equals(a[i])) {
                return false;
            }
        }
        if(b[i] != a[i]) {
            return false;
        }
    }
    for(i in b) {
        if(typeof a[i] == 'undefined') {
            return false;
        }
        if(typeof a[i] == 'object') {
            if(!a[i].equals(b[i])) {
                return false;
            }
        }
        if(a[i] != b[i]) {
            return false;
        }
    }
    return true;
}

var a = {foo:'bar', bar: {blub:'bla'}};
var b = {foo:'bar', bar: {blub:'blob'}};
alert(a.equals(b)); // alert's a false

#6楼

I have modified a bit the code above. 我已经修改了上面的代码。 for me 0 !== false and null !== undefined . 对我来说0!== falsenull!== undefined If you do not need such strict check remove one " = " sign in " this[p] !== x[p] " inside the code. 如果您不需要这样严格的检查,请在代码中删除一个“ = ”登录“ this [p]!== x [p] ”。

Object.prototype.equals = function(x){
    for (var p in this) {
        if(typeof(this[p]) !== typeof(x[p])) return false;
        if((this[p]===null) !== (x[p]===null)) return false;
        switch (typeof(this[p])) {
            case 'undefined':
                if (typeof(x[p]) != 'undefined') return false;
                break;
            case 'object':
                if(this[p]!==null && x[p]!==null && (this[p].constructor.toString() !== x[p].constructor.toString() || !this[p].equals(x[p]))) return false;
                break;
            case 'function':
                if (p != 'equals' && this[p].toString() != x[p].toString()) return false;
                break;
            default:
                if (this[p] !== x[p]) return false;
        }
    }
    return true;
}

Then I have tested it with next objects: 然后,我用下一个对象对其进行了测试:

var a = {a: 'text', b:[0,1]};
var b = {a: 'text', b:[0,1]};
var c = {a: 'text', b: 0};
var d = {a: 'text', b: false};
var e = {a: 'text', b:[1,0]};
var f = {a: 'text', b:[1,0], f: function(){ this.f = this.b; }};
var g = {a: 'text', b:[1,0], f: function(){ this.f = this.b; }};
var h = {a: 'text', b:[1,0], f: function(){ this.a = this.b; }};
var i = {
    a: 'text',
    c: {
        b: [1, 0],
        f: function(){
            this.a = this.b;
        }
    }
};
var j = {
    a: 'text',
    c: {
        b: [1, 0],
        f: function(){
            this.a = this.b;
        }
    }
};
var k = {a: 'text', b: null};
var l = {a: 'text', b: undefined};

a==b expected true; a == b预期为true; returned true 返回真

a==c expected false; a == c预期为false; returned false 返回假

c==d expected false; c == d预期为假; returned false 返回假

a==e expected false; a == e预期为假; returned false 返回假

f==g expected true; f == g预期为真; returned true 返回真

h==g expected false; h == g预期为假; returned false 返回假

i==j expected true; i == j预期为真; returned true 返回真

d==k expected false; d == k预期为假; returned false 返回假

k==l expected false; k == l预期为假; returned false 返回假

发布了0 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/p15097962069/article/details/105307184