Hướng dẫn how does object comparison work in javascript? - so sánh đối tượng hoạt động như thế nào trong javascript?

Thật không may, không có cách nào hoàn hảo, trừ khi bạn sử dụng

 x = {a: 1, b: 2};
 y = {b: 2, a: 1};
3 một cách đệ quy và truy cập tất cả các thuộc tính không thể kích thích, nhưng điều này chỉ hoạt động trong Firefox.

Vì vậy, điều tốt nhất tôi có thể làm là đoán các kịch bản sử dụng.


1) Nhanh chóng và hạn chế.

Hoạt động khi bạn có các đối tượng kiểu JSON đơn giản mà không có phương thức và các nút dom bên trong:

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

Thứ tự của các thuộc tính rất quan trọng, vì vậy phương thức này sẽ trả về sai cho các đối tượng sau:

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

2) Chậm và chung chung hơn.

So sánh các đối tượng mà không cần đào thành các nguyên mẫu, sau đó so sánh các hình chiếu của các thuộc tính đệ quy và cũng so sánh các hàm tạo.

Đây là thuật toán gần như chính xác:

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

Các vấn đề đã biết (tốt, chúng có mức độ ưu tiên rất thấp, có lẽ bạn sẽ không bao giờ nhận thấy chúng):

  • các đối tượng có cấu trúc nguyên mẫu khác nhau nhưng cùng một hình chiếu
  • Các chức năng có thể có văn bản giống hệt nhau nhưng tham khảo các đóng cửa khác nhau

Các bài kiểm tra: Các bài kiểm tra vượt qua là từ cách xác định bình đẳng cho hai đối tượng JavaScript ?. passes tests are from How to determine equality for two JavaScript objects?.

Hướng dẫn how does object comparison work in javascript? - so sánh đối tượng hoạt động như thế nào trong javascript?

Đã trả lời ngày 17 tháng 7 năm 2009 lúc 16:08Jul 17, 2009 at 16:08

7

Đây là giải pháp nhận xét ES3 của tôi (chi tiết Gory sau mã):ES3 commented solution (gory details after the code):

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

Khi phát triển giải pháp này, tôi đã có một cái nhìn cụ thể về các trường hợp góc, hiệu quả, nhưng cố gắng mang lại một giải pháp đơn giản hoạt động, hy vọng với một số thanh lịch. JavaScript cho phép cả các thuộc tính và đối tượng không xác định và không xác định có các chuỗi nguyên mẫu có thể dẫn đến các hành vi rất khác nhau nếu không được kiểm tra.null and undefined properties and objects have prototypes chains that can lead to very different behaviors if not checked.

Đầu tiên tôi đã chọn không mở rộng đối tượng. Ngoài ra còn có những mối quan tâm chính đáng khác được ghi nhận bởi những người khác liên quan đến việc mở rộng đối tượng.prototype về các tác dụng phụ có thể có trên mã của người khác.Object.prototype, mostly because null could not be one of the objects of the comparison and that I believe that null should be a valid object to compare with another. There are also other legitimate concerns noted by others regarding the extension of Object.prototype regarding possible side effects on other's code.

Đặc biệt phải cẩn thận để xử lý khả năng JavaScript cho phép các thuộc tính đối tượng có thể được đặt thành không xác định, tức là có các thuộc tính tồn tại mà các giá trị được đặt thành không xác định. Giải pháp trên xác minh rằng cả hai đối tượng đều có cùng các thuộc tính được đặt thành không xác định để báo cáo bình đẳng. Điều này chỉ có thể được thực hiện bằng cách kiểm tra sự tồn tại của các thuộc tính bằng đối tượng.hasownProperty (Property_name). Cũng lưu ý rằng json.Stringify () loại bỏ các thuộc tính được đặt thành không xác định và do đó so sánh bằng cách sử dụng biểu mẫu này sẽ bỏ qua các thuộc tính được đặt thành giá trị không xác định.undefined, i.e. there exists properties which values are set to undefined. The above solution verifies that both objects have the same properties set to undefined to report equality. This can only be accomplished by checking the existence of properties using Object.hasOwnProperty( property_name ). Also note that JSON.stringify() removes properties that are set to undefined, and that therefore comparisons using this form will ignore properties set to the value undefined.

Các chức năng chỉ được coi là bằng nhau nếu chúng chia sẻ cùng một tài liệu tham khảo, không chỉ cùng một mã, bởi vì điều này sẽ không tính đến nguyên mẫu các chức năng này. Vì vậy, việc so sánh chuỗi mã không hoạt động để đảm bảo rằng chúng có cùng một đối tượng nguyên mẫu.

Hai đối tượng nên có cùng một chuỗi nguyên mẫu, không chỉ các thuộc tính giống nhau. Điều này chỉ có thể được kiểm tra trình duyệt chéo bằng cách so sánh hàm tạo của cả hai đối tượng cho sự bình đẳng nghiêm ngặt. Ecmascript 5 sẽ cho phép kiểm tra nguyên mẫu thực tế của họ bằng cách sử dụng object.getPrototype (). Một số trình duyệt web cũng cung cấp một thuộc tính __proto__ làm điều tương tự. Một cải tiến có thể của mã trên sẽ cho phép sử dụng một trong những phương pháp này bất cứ khi nào có sẵn.prototype chain, not just the same properties. This can only be tested cross-browser by comparing the constructor of both objects for strict equality. ECMAScript 5 would allow to test their actual prototype using Object.getPrototypeOf(). Some web browsers also offer a __proto__ property that does the same thing. A possible improvement of the above code would allow to use one of these methods whenever available.

Việc sử dụng các so sánh nghiêm ngặt là tối quan trọng ở đây vì 2 không nên được coi là bằng "2.0000", cũng không phải sai nên được coi là bằng null, không xác định hoặc 0.2 should not be considered equal to "2.0000", nor false should be considered equal to null, undefined, or 0.

Cân nhắc hiệu quả dẫn tôi đến so sánh với sự bình đẳng của các tài sản càng sớm càng tốt. Sau đó, chỉ khi điều đó thất bại, hãy tìm loại các thuộc tính này. Việc tăng tốc độ có thể có ý nghĩa trên các đối tượng lớn với rất nhiều tính chất vô hướng.typeof these properties. The speed boost could be significant on large objects with lots of scalar properties.

Không còn hai vòng lặp, cần phải kiểm tra các thuộc tính từ đối tượng bên trái, thứ hai để kiểm tra các thuộc tính từ bên phải và xác minh chỉ tồn tại (không giá trị), để bắt các thuộc tính này được xác định với giá trị không xác định.undefined value.

Nhìn chung, mã này xử lý hầu hết các trường hợp góc chỉ trong 16 dòng mã (không có bình luận).


Cập nhật (8/13/2015). Tôi đã triển khai một phiên bản tốt hơn, vì hàm giá trị_equals () nhanh hơn, xử lý các trường hợp góc đúng như nan và 0 khác với -0, tùy chọn thực thi thứ tự thuộc tính của các đối tượng và kiểm tra các tài liệu tham khảo theo chu kỳ, được hỗ trợ bởi hơn 100 thử nghiệm tự động Là một phần của bộ thử nghiệm dự án Toubkal.. I have implemented a better version, as the function value_equals() that is faster, handles properly corner cases such as NaN and 0 different than -0, optionally enforcing objects' properties order and testing for cyclic references, backed by more than 100 automated tests as part of the Toubkal project test suite.

Đã trả lời ngày 15 tháng 7 năm 2011 lúc 22:21Jul 15, 2011 at 22:21

Jean Vincentjean VincentJean Vincent

11,5K7 Huy hiệu vàng32 Huy hiệu bạc24 Huy hiệu đồng7 gold badges32 silver badges24 bronze badges

0

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

Cách đơn giản để so sánh các đối tượng chỉ một cấp.

Đã trả lời ngày 2 tháng 5 năm 2011 lúc 15:27May 2, 2011 at 15:27

Pincopallopincopallopincopallo

6235 Huy hiệu bạc2 Huy hiệu Đồng5 silver badges2 bronze badges

1

Chắc chắn không phải là cách duy nhất - bạn có thể tạo mẫu cho một phương thức (so với đối tượng ở đây nhưng tôi chắc chắn sẽ không đề xuất sử dụng đối tượng cho mã trực tiếp) để sao chép các phương thức so sánh kiểu C#/Java.

Chỉnh sửa, vì một ví dụ chung dường như được mong đợi:

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

Lưu ý rằng các phương pháp thử nghiệm với toString () hoàn toàn không đủ tốt nhưng một phương pháp có thể chấp nhận được là rất khó vì vấn đề của khoảng trắng có ý nghĩa hay không, không bao giờ để tâm đến các phương pháp và phương pháp từ đồng nghĩa tạo ra kết quả tương tự với các triển khai khác nhau. Và các vấn đề của tạo mẫu chống lại đối tượng nói chung.

Đã trả lời ngày 1 tháng 7 năm 2009 lúc 12:25Jul 1, 2009 at 12:25

Annakataannakataannakata

73.2K16 Huy hiệu vàng113 Huy hiệu bạc180 Huy hiệu Đồng16 gold badges113 silver badges180 bronze badges

0

Thuật toán sau đây sẽ xử lý các cấu trúc dữ liệu tự tham chiếu, số, chuỗi, ngày và tất nhiên các đối tượng JavaScript lồng nhau đơn giản:

Đối tượng được coi là tương đương khi

  • Chúng chính xác bằng nhau trên mỗi
     x = {a: 1, b: 2};
     y = {b: 2, a: 1};
    
    4 (chuỗi và số được mở ra trước tiên để đảm bảo
     x = {a: 1, b: 2};
     y = {b: 2, a: 1};
    
    5 tương đương với
     x = {a: 1, b: 2};
     y = {b: 2, a: 1};
    
    6)
  • hoặc cả hai đều là ngày và có cùng
     x = {a: 1, b: 2};
     y = {b: 2, a: 1};
    
    7
  • Hoặc cả hai đều giống nhau và không phải null và ...
    • Chúng không phải là đối tượng và bằng nhau trên mỗi
       x = {a: 1, b: 2};
       y = {b: 2, a: 1};
      
      8 (bắt số/chuỗi/booleans)
    • Hoặc, bỏ qua các thuộc tính có giá trị
       x = {a: 1, b: 2};
       y = {b: 2, a: 1};
      
      9 Chúng có cùng các thuộc tính tất cả đều được coi là tương đương đệ quy.

Các chức năng không được coi là giống hệt nhau bởi văn bản chức năng. Thử nghiệm này là không đủ vì các chức năng có thể có các đóng cửa khác nhau. Các chức năng chỉ được coi là bằng nhau nếu

 x = {a: 1, b: 2};
 y = {b: 2, a: 1};
4 nói như vậy (nhưng bạn có thể dễ dàng mở rộng mối quan hệ tương đương đó nếu bạn chọn làm như vậy). are not considered identical by function text. This test is insufficient because functions may have differing closures. Functions are only considered equal if
 x = {a: 1, b: 2};
 y = {b: 2, a: 1};
4 says so (but you could easily extend that equivalent relation should you choose to do so).

Các vòng lặp vô hạn, có khả năng gây ra bởi các cơ sở dữ liệu tròn, được tránh. Khi

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;
}
1 cố gắng từ chối sự bình đẳng và đệ quy vào các thuộc tính của một đối tượng để làm như vậy, nó sẽ theo dõi các đối tượng mà cần có so sánh phụ này. Nếu sự bình đẳng có thể bị từ chối, thì một số đường dẫn thuộc tính có thể tiếp cận khác nhau giữa các đối tượng, và sau đó phải có một đường dẫn ngắn nhất có thể tiếp cận và đường dẫn ngắn nhất có thể tiếp cận nhất không thể chứa các chu kỳ có trong cả hai đường dẫn; tức là có thể giả định sự bình đẳng khi so sánh các đối tượng đệ quy. Giả định được lưu trữ trong một thuộc tính
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;
}
2, bị xóa sau khi sử dụng, nhưng nếu biểu đồ đối tượng đã chứa một thuộc tính như vậy, hành vi không được xác định. Việc sử dụng thuộc tính đánh dấu như vậy là cần thiết vì JavaScript không hỗ trợ từ điển bằng cách sử dụng các đối tượng tùy ý làm khóa.
, potentially caused by circular datastructures, are avoided. When
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;
}
1 attempts to disprove equality and recurses into an object's properties to do so, it keeps track of the objects for which this sub-comparison is needed. If equality can be disproved, then some reachable property path differs between the objects, and then there must be a shortest such reachable path, and that shortest reachable path cannot contain cycles present in both paths; i.e. it is OK to assume equality when recursively comparing objects. The assumption is stored in a property
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;
}
2, which is deleted after use, but if the object graph already contains such a property, behavior is undefined. The use of such a marker property is necessary because javascript doesn't support dictionaries using arbitrary objects as keys.

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

Đã trả lời ngày 19 tháng 6 năm 2011 lúc 14:29Jun 19, 2011 at 14:29

Eamon Nerbonneamon NerbonneEamon Nerbonne

45,8K19 Huy hiệu vàng95 Huy hiệu bạc165 Huy hiệu Đồng19 gold badges95 silver badges165 bronze badges

1

Tôi đã viết đoạn mã này để so sánh đối tượng, và nó dường như hoạt động. Kiểm tra các xác nhận:


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

Đã trả lời ngày 3 tháng 10 năm 2010 lúc 11:01Oct 3, 2010 at 11:01

mhomsmhomsmhoms

1891 Huy hiệu bạc 6 Huy hiệu đồng1 silver badge6 bronze badges

1

Tôi đã sửa đổi một chút mã ở trên. Đối với tôi 0! == FALSE và NULL! == Không xác định. Nếu bạn không cần kiểm tra nghiêm ngặt như vậy, hãy xóa một "=" Đăng nhập "Điều này [p]! == x [p]" bên trong mã.

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

Sau đó, tôi đã thử nghiệm nó với các đối tượng tiếp theo:

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 mong đợi đúng; trả lại đúng

A == C dự kiến ​​sai; trả lại sai

c == D dự kiến ​​sai; trả lại sai

a == e dự kiến ​​sai; trả lại sai

f == g mong đợi đúng; trả lại đúng

h == g mong đợi sai; trả lại sai

i == j mong đợi đúng; trả lại đúng

d == k dự kiến ​​sai; trả lại sai

k == L mong đợi sai; trả lại sai

Đã trả lời ngày 29 tháng 4 năm 2010 lúc 9:17Apr 29, 2010 at 9:17

Hướng dẫn how does object comparison work in javascript? - so sánh đối tượng hoạt động như thế nào trong javascript?

1

Đây là phiên bản của tôi, khá nhiều thứ từ chủ đề này được tích hợp (cùng số lượng cho các trường hợp thử nghiệm):

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

Đây là Testcase của tôi:

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

Đã trả lời ngày 2 tháng 4 năm 2011 lúc 11:39Apr 2, 2011 at 11:39

Gossigossigossi

5445 Huy hiệu bạc16 Huy hiệu Đồng5 silver badges16 bronze badges

3

Nếu bạn làm việc mà không có thư viện JSON, có lẽ điều này sẽ giúp bạn:

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

Hướng dẫn how does object comparison work in javascript? - so sánh đối tượng hoạt động như thế nào trong javascript?

Đã trả lời ngày 9 tháng 3 năm 2010 lúc 10:38Mar 9, 2010 at 10:38

2

Nếu bạn muốn kiểm tra các phương thức rõ ràng, bạn có thể sử dụng phương thức.tosource () hoặc phương thức.ToString () phương thức.

Đã trả lời ngày 1 tháng 7 năm 2009 lúc 15:44Jul 1, 2009 at 15:44

Nicolas rnicolas rNicolas R

9722 Huy hiệu vàng8 Huy hiệu bạc17 Huy hiệu đồng2 gold badges8 silver badges17 bronze badges

5

Làm thế nào là các đối tượng so sánh trong JavaScript?

Thông thường, khi bạn so sánh các loại dữ liệu như INT và chuỗi trong JavaScript, bạn sử dụng các toán tử bình đẳng (== và ===). Tuy nhiên, so sánh các đối tượng với == và === sẽ không hoạt động. Để khắc phục điều này, một tùy chọn là xâu chuỗi cả hai đối tượng và sau đó sử dụng các toán tử bình đẳng.use the equality operators ( == and === ). However, comparing objects with == and === will not work. To fix this, one option is to stringify both objects and then use the equality operators.

Làm thế nào để bình đẳng đối tượng hoạt động trong JS?

Nếu hai giá trị có cùng loại, chúng được coi là bằng nhau.== (bằng kép) là toán tử bình đẳng lỏng lẻo. Nó chuyển đổi cả hai giá trị thành một loại chung và sau đó kiểm tra chức năng Equality.Object.is ().== (double equals) is the loose equality operator. It converts both the values to a common type and then checks for equality. object.is() function.

Bạn có thể kiểm tra xem hai đối tượng có bằng nhau không?

Trong JavaScript, chúng ta không thể so sánh trực tiếp hai đối tượng với các toán tử bình đẳng (bằng kép bằng == hoặc ba bằng ===) để xem chúng có bằng hay không.So sánh hai đối tượng như thế này dẫn đến sai ngay cả khi chúng có cùng một dữ liệu.we cannot directly compare two objects by equality operators (double equals == or triple equals ===) to see whether they are equal or not. Comparing two objects like this results in false even if they have the same data.

Làm thế nào để bạn so sánh hai đối tượng?

Trong khi phương thức bằng () so sánh hai đối tượng.Các đối tượng bằng nhau khi chúng có cùng trạng thái (thường so sánh các biến).Các đối tượng giống hệt nhau khi họ chia sẻ danh tính lớp.Ví dụ, biểu thức obj1 == obj2 kiểm tra danh tính, không bình đẳng.the equals() method compares two objects. Objects are equal when they have the same state (usually comparing variables). Objects are identical when they share the class identity. For example, the expression obj1==obj2 tests the identity, not equality.