JavaScript中的对象比较

1467

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

示例:

var user1 = {name : "nerd", org: "dev"};
var user2 = {name : "nerd", org: "dev"};
var eq = user1 == user2;
alert(eq); // gives false
我知道只有当两个对象指向完全相同的对象时,它们才相等,但是有没有一种方法可以检查它们是否具有相同的属性值?
下面这种方式对我有效,但这是唯一的可能性吗?
var eq = Object.toJSON(user1) == Object.toJSON(user2);
alert(eq); // gives true

2
我在这个主题上进行了一些调整,并设计出了一个灵活的解决方案来解决问题http://stamat.wordpress.com/2013/06/22/javascript-object-comparison/。 - stamat
2
测试(深度)相等性是一个相当难以正确实现的事情。请前往 https://github.com/loveencounterflow/jseq 查看涵盖许多边缘情况的流行 equal() 实现的测试套件。文档中的讨论也十分详细。 - flow
50
使用lodash库,它的isEqual方法恰好符合你的需求。 - Adam Fraser
2
使用https://facebook.github.io/immutable-js/,这个操作将变得非常简单和快速。 - Lukas Liesis
12
使用下划线库,_.isEqual(obj1, obj2) - Sai Ram
显示剩余14条评论
10个回答

1760

很遗憾,除非您递归使用_proto_并访问所有不可枚举属性,否则没有完美的方法,但这仅适用于Firefox。

因此,我能做的最好的事情就是猜测使用场景。


1)快速和有限。

适用于没有方法和DOM节点的简单JSON风格对象:

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

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

  • 具有不同原型结构但投影相同的对象
  • 函数可能具有相同的文本但引用不同的闭包

测试: 通过测试来自于如何确定两个JavaScript对象的相等性?


14
当一个属性被定义但被设置为“undefined”值时,检查未定义将失败。使用in运算符而不是typeof可以避免这种情况:p in x。通过字符串值比较函数非常不可靠,除了通常函数分解失败的原因外,由于闭包,拥有相同代码但行为非常不同的两个函数也很常见。例如,任何由jQuery的$.proxy或Prototype的Function#bind创建的函数。我建议仅使用函数标识进行比较。 - bobince
25
我认为你应该使用“全等”比较运算符:===,因为{ a: 5 }{ a: "5.0" }并不相等,或者它们是相等的吗? - Crozin
30
如果可以避免的话,就不应该扩展Object.prototype。这会导致一些丑陋的问题,比如如果在循环内没有加上if(!someObject.hasOwnProperty(key)) continue;,则会破坏 for(var key in someObject) 的功能。 - ThiefMaster
12
函数比较有误:函数可能具有相同的文本但引用不同的闭包。更好的方法是只返回this[p] === x[p] - Eamon Nerbonne
21
关于 1) "The ORDER of the properties IS IMPORTANT, so this method will return false for following objects:" 这句话不一定准确。这个方法对于这些对象可能会返回 false,也可能不会。没有任何保证。这就是为什么我们不使用 JSON.stringify 来比较对象。因为属性的顺序没有保证。 - user2437417
显示剩余4条评论

226

这是我的ES3注释解决方案(代码后面有详细信息):

function object_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.

  for ( var 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 ( ! object_equals( x[ p ],  y[ p ] ) ) return false;
      // Objects and Arrays must be tested recursively
  }

  for ( p in y )
    if ( y.hasOwnProperty( p ) && ! x.hasOwnProperty( p ) )
      return false;
        // allows x[ p ] to be set to undefined

  return true;
}

在开发这个解决方案时,我特别关注了边界情况、效率和简单性,希望能创造一个既有效又优雅的解决方案。JavaScript允许nullundefined属性和对象具有原型链,如果不进行检查,可能会导致非常不同的行为。
首先,我选择不扩展Object.prototype,主要是因为null不能成为比较的对象之一,而且我认为null应该是与另一个对象进行比较的有效对象。其他人也注意到了关于扩展Object.prototype可能对其他代码产生副作用的合法问题。
必须特别注意处理JavaScript允许将对象属性设置为undefined的可能性,即存在值设置为undefined的属性。上述解决方案验证两个对象是否具有相同的设置为undefined的属性以报告相等性。这只能通过使用Object.hasOwnProperty( property_name )来检查属性的存在来实现。还要注意,JSON.stringify()会删除设置为undefined的属性,因此使用该形式进行比较将忽略设置为值undefined的属性。
只有当两个函数具有相同的引用而不仅仅是相同的代码时,它们才应被视为相等,因为这不会考虑到这些函数的原型。因此,仅比较代码字符串无法保证它们具有相同的原型对象。
这两个对象应该有相同的原型链,而不仅仅是相同的属性。只有通过比较两个对象的构造函数是否严格相等才能在各种浏览器中进行测试。ECMAScript 5将允许使用Object.getPrototypeOf()来测试它们的实际原型。一些Web浏览器还提供了一个__proto__属性,它也可以完成同样的功能。以上代码的一个可能的改进是,在可用的情况下使用其中一种方法。
在这里使用严格比较非常重要,因为2不应被视为等于"2.0000",false也不应被视为等于null、undefined或0。
为了效率考虑,我尽早比较属性的相等性。然后,仅当失败时,查找这些属性的typeof。在具有大量标量属性的大型对象上,速度提升可能非常显著。
只需要两个循环,第一个检查左对象的属性,第二个检查右对象的属性并验证存在性(而不是值),以捕获使用undefined值定义的这些属性。

总的来说,这段代码只有16行(不包括注释)就处理了大多数边角情况。


更新(2015年8月13日)。我已经实现了一个更好的版本,使用value_equals()函数速度更快,能够正确处理NaN和0与-0不同的特殊情况,可选择强制对象属性顺序并测试循环引用,作为Toubkal项目测试套件的一部分,支持超过100个自动化测试

59
  Utils.compareObjects = function(o1, o2){
    for(var p in o1){
        if(o1.hasOwnProperty(p)){
            if(o1[p] !== o2[p]){
                return false;
            }
        }
    }
    for(var p in o2){
        if(o2.hasOwnProperty(p)){
            if(o1[p] !== o2[p]){
                return false;
            }
        }
    }
    return true;
};

比较仅限于单级对象的简单方法。


这并不是很高效,因为如果两个对象相等,每个属性都会被比较两次。 - Malvineous

23

这绝不是唯一的方法 - 您可以原型化一个方法(此处针对Object,但我绝不建议在实际代码中使用Object)来复制C#/Java风格的比较方法。

编辑,由于似乎需要提供一个通用示例:

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

请注意,使用toString()方法进行测试绝对不够好,但是一个可以接受的方法非常困难,因为空格是否具有意义,别提同义词方法和以不同实现产生相同结果的方法了。 还有一般情况下原型与对象之间的问题。


21
以下算法将处理自引用数据结构、数字、字符串、日期以及纯嵌套的javascript对象:
当两个对象满足以下条件时被视为相等:
- 它们通过 `===` 操作符完全相等(对于字符串和数字,先解开包装以确保 `42` 等价于 `Number(42)`) - 或者它们都是日期对象且具有相同的 `valueOf()` 值 - 或者它们都是相同类型的非空对象且... - 它们不是对象且可以通过 `==` 进行比较(捕获数字/字符串/布尔值) - 或者忽略值为 `undefined` 的属性,它们具有相同的属性,其中所有属性都被认为是递归等效的。
函数不会根据函数文本被视为相同。这个测试是不够充分的,因为函数可能具有不同的闭包。只有当 `===` 操作符判断它们相等时,函数才会被视为相等(但是如果您选择这样做,可以轻松地扩展此等价关系)。
避免了由循环数据结构导致的无限循环。当 `areEquivalent` 尝试证明不等性并递归到一个对象的属性中进行比较时,它会跟踪需要进行此子比较的对象。如果可以证明不等性,则一些可达的属性路径在两个对象之间存在差异,然后必须有一个最短的可达路径,并且该最短的可达路径不能包含在两个路径中都存在的循环;即,在递归比较对象时可以假定相等性。这种假设存储在属性 `areEquivalent_Eq_91_2_34` 中,在使用后将被删除,但是如果对象图已经包含这样的属性,则行为未定义。使用此标记属性是必要的,因为JavaScript不支持使用任意对象作为键的字典。
function unwrapStringOrNumber(obj) {
    return (obj instanceof Number || obj instanceof String 
            ? obj.valueOf() 
            : obj);
}
function areEquivalent(a, b) {
    a = unwrapStringOrNumber(a);
    b = unwrapStringOrNumber(b);
    if (a === b) return true; //e.g. a and b both null
    if (a === null || b === null || typeof (a) !== typeof (b)) return false;
    if (a instanceof Date) 
        return b instanceof Date && a.valueOf() === b.valueOf();
    if (typeof (a) !== "object") 
        return a == b; //for boolean, number, string, xml

    var newA = (a.areEquivalent_Eq_91_2_34 === undefined),
        newB = (b.areEquivalent_Eq_91_2_34 === undefined);
    try {
        if (newA) a.areEquivalent_Eq_91_2_34 = [];
        else if (a.areEquivalent_Eq_91_2_34.some(
            function (other) { return other === b; })) return true;
        if (newB) b.areEquivalent_Eq_91_2_34 = [];
        else if (b.areEquivalent_Eq_91_2_34.some(
            function (other) { return other === a; })) return true;
        a.areEquivalent_Eq_91_2_34.push(b);
        b.areEquivalent_Eq_91_2_34.push(a);

        var tmp = {};
        for (var prop in a) 
            if(prop != "areEquivalent_Eq_91_2_34") 
                tmp[prop] = null;
        for (var prop in b) 
            if (prop != "areEquivalent_Eq_91_2_34") 
                tmp[prop] = null;

        for (var prop in tmp) 
            if (!areEquivalent(a[prop], b[prop]))
                return false;
        return true;
    } finally {
        if (newA) delete a.areEquivalent_Eq_91_2_34;
        if (newB) delete b.areEquivalent_Eq_91_2_34;
    }
}

1
仍在处理复杂嵌套对象,谢谢。 - Waxim Corp

17

我编写了这段对象比较的代码,它似乎有效。检查断言:


function countProps(obj) {
    var count = 0;
    for (k in obj) {
        if (obj.hasOwnProperty(k)) {
            count++;
        }
    }
    return count;
};

function objectEquals(v1, v2) {

    if (typeof(v1) !== typeof(v2)) {
        return false;
    }

    if (typeof(v1) === "function") {
        return v1.toString() === v2.toString();
    }

    if (v1 instanceof Object && v2 instanceof Object) {
        if (countProps(v1) !== countProps(v2)) {
            return false;
        }
        var r = true;
        for (k in v1) {
            r = objectEquals(v1[k], v2[k]);
            if (!r) {
                return false;
            }
        }
        return true;
    } else {
        return v1 === v2;
    }
}

assert.isTrue(objectEquals(null,null));
assert.isFalse(objectEquals(null,undefined));

assert.isTrue(objectEquals("hi","hi"));
assert.isTrue(objectEquals(5,5));
assert.isFalse(objectEquals(5,10));

assert.isTrue(objectEquals([],[]));
assert.isTrue(objectEquals([1,2],[1,2]));
assert.isFalse(objectEquals([1,2],[2,1]));
assert.isFalse(objectEquals([1,2],[1,2,3]));

assert.isTrue(objectEquals({},{}));
assert.isTrue(objectEquals({a:1,b:2},{a:1,b:2}));
assert.isTrue(objectEquals({a:1,b:2},{b:2,a:1}));
assert.isFalse(objectEquals({a:1,b:2},{a:1,b:3}));

assert.isTrue(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}));
assert.isFalse(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:27}}));

assert.isTrue(objectEquals(function(x){return x;},function(x){return x;}));
assert.isFalse(objectEquals(function(x){return x;},function(y){return y+2;}));

在for循环中在k之前放置let会导致错误。 - Syed Mohib Uddin

6

我稍微修改了上面的代码。对我来说,0 !== falsenull !== undefined。如果您不需要这样严格的检查,请在代码中的"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;
}

接下来,我对以下对象进行了测试:

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 预期结果为true;实际返回结果为true

a==c 预期结果为false;实际返回结果为false

c==d 预期结果为false;实际返回结果为false

a==e 预期结果为false;实际返回结果为false

f==g 预期结果为true;实际返回结果为true

h==g 预期结果为false;实际返回结果为false

i==j 预期结果为true;实际返回结果为true

d==k 预期结果为false;实际返回结果为false

k==l 预期结果为false;实际返回结果为false


测试构造函数或子对象加1。但为什么不测试主对象的构造函数?为什么不通过引用测试函数,而是使用toString()比较字符串,这样会很慢且不准确。 - Jean Vincent

4

这是我的版本,基本上整合了这个主题中的大部分内容(测试用例也是如此):

Object.defineProperty(Object.prototype, "equals", {
    enumerable: false,
    value: function (obj) {
        var p;
        if (this === obj) {
            return true;
        }

        // some checks for native types first

        // function and sring
        if (typeof(this) === "function" || typeof(this) === "string" || this instanceof String) { 
            return this.toString() === obj.toString();
        }

        // number
        if (this instanceof Number || typeof(this) === "number") {
            if (obj instanceof Number || typeof(obj) === "number") {
                return this.valueOf() === obj.valueOf();
            }
            return false;
        }

        // null.equals(null) and undefined.equals(undefined) do not inherit from the 
        // Object.prototype so we can return false when they are passed as obj
        if (typeof(this) !== typeof(obj) || obj === null || typeof(obj) === "undefined") {
            return false;
        }

        function sort (o) {
            var result = {};

            if (typeof o !== "object") {
                return o;
            }

            Object.keys(o).sort().forEach(function (key) {
                result[key] = sort(o[key]);
            });

            return result;
        }

        if (typeof(this) === "object") {
            if (Array.isArray(this)) { // check on arrays
                return JSON.stringify(this) === JSON.stringify(obj);                
            } else { // anyway objects
                for (p in this) {
                    if (typeof(this[p]) !== typeof(obj[p])) {
                        return false;
                    }
                    if ((this[p] === null) !== (obj[p] === null)) {
                        return false;
                    }
                    switch (typeof(this[p])) {
                    case 'undefined':
                        if (typeof(obj[p]) !== 'undefined') {
                            return false;
                        }
                        break;
                    case 'object':
                        if (this[p] !== null 
                                && obj[p] !== null 
                                && (this[p].constructor.toString() !== obj[p].constructor.toString() 
                                        || !this[p].equals(obj[p]))) {
                            return false;
                        }
                        break;
                    case 'function':
                        if (this[p].toString() !== obj[p].toString()) {
                            return false;
                        }
                        break;
                    default:
                        if (this[p] !== obj[p]) {
                            return false;
                        }
                    }
                };

            }
        }

        // at least check them with JSON
        return JSON.stringify(sort(this)) === JSON.stringify(sort(obj));
    }
});

这是我的测试用例:

    assertFalse({}.equals(null));
    assertFalse({}.equals(undefined));

    assertTrue("String", "hi".equals("hi"));
    assertTrue("Number", new Number(5).equals(5));
    assertFalse("Number", new Number(5).equals(10));
    assertFalse("Number+String", new Number(1).equals("1"));

    assertTrue([].equals([]));
    assertTrue([1,2].equals([1,2]));
    assertFalse([1,2].equals([2,1]));
    assertFalse([1,2].equals([1,2,3]));

    assertTrue(new Date("2011-03-31").equals(new Date("2011-03-31")));
    assertFalse(new Date("2011-03-31").equals(new Date("1970-01-01")));

    assertTrue({}.equals({}));
    assertTrue({a:1,b:2}.equals({a:1,b:2}));
    assertTrue({a:1,b:2}.equals({b:2,a:1}));
    assertFalse({a:1,b:2}.equals({a:1,b:3}));

    assertTrue({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}));
    assertFalse({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:27}}));

    assertTrue("Function", (function(x){return x;}).equals(function(x){return x;}));
    assertFalse("Function", (function(x){return x;}).equals(function(y){return y+2;}));

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

    assertTrue(a.equals(b));
    assertFalse(a.equals(c));
    assertFalse(c.equals(d));
    assertFalse(a.equals(e));
    assertTrue(f.equals(g));
    assertFalse(h.equals(g));
    assertTrue(i.equals(j));
    assertFalse(d.equals(k));
    assertFalse(k.equals(l));

JSON.stringify()会移除被设置为undefined的属性,因此使用这种形式进行比较将忽略被设置为undefined的属性:assertFalse([1,2,null].equals([1,2,undefined]))。 - Jean Vincent
你正在将数组字符串化,但是数组内部可能有复杂的对象。 - Dan
这个测试应该断言false而不是true,因为一个是Object的实例,另一个是原始类型。assertTrue("Number", new Number(5).equals(5)); - Pete Alvin

3
如果您在没有使用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

13
这是一个不好的想法。修改Object.prototype可能会有各种未预见的后果。 - MarcF
3
您无法在没有JSON库的情况下工作,它是JavaScript标准库的一部分: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects - Gerard Simpson

2

如果您想明确检查方法,可以使用method.toSource()或method.toString()方法。


真的不够好,原因如我所述。 - annakata
那么你需要遍历对象的元素,检查它们的类型,当你找到一个函数时使用 toSource() 或 toString() 函数? - Nosredna
Nosredna,是的。这会给你实际函数的文本。annakata,我不理解什么不够好,以及你实际上想要做什么。你能详细说明一下吗? - Nicolas R
2
@snz3 - 空格、丢失的分号、大括号和类似的语法差异存在严重问题,这可能会产生影响,并且很难在不解析即从原始字符串格式中解耦的情况下确定。还有波动状态和原型的问题。基本上,字符串不能很好地捕捉两个对象的状态。 - annakata
2
你好,来自2021年的消息,toSource已经被弃用,请勿使用。 - hazer_hazer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接