Сравнение объектов в JavaScript [дубликат]

На самом деле, я думаю, что это лучший способ.

from django.core.validators import URLValidator
from django.core.exceptions import ValidationError

val = URLValidator(verify_exists=False)
try:
    val('http://www.google.com')
except ValidationError, e:
    print e

Если вы установите verify_exists на True, он действительно проверит, существует ли URL-адрес, иначе он просто проверит,

edit: ah yeah, этот вопрос является дубликатом этого: Как проверить, существует ли URL с валидаторами Django?

947
задан Matt 10 May 2016 в 19:43
поделиться

5 ответов

К сожалению, идеального способа не существует, если только вы не используете _proto_ рекурсивно и не обращаетесь ко всем неперечисляемым свойствам, но это работает только в Firefox.

Итак, лучшее, что я можно угадать сценарии использования.


1) Быстро и ограниченно.

Работает, когда у вас есть простые объекты в стиле JSON без методов и узлов DOM внутри:

 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? ].

1232
ответ дан 19 December 2019 в 20:20
поделиться

Я немного изменил код выше. для меня 0! == false и null! == 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

a == c ожидал false; вернул ложь

c == d ожидал ложь; вернул ложь

a == e ожидал ложь; вернул false

f == g ожидал true; вернул true

h == g ожидал false; вернул false

i == j ожидал true; вернул true

d == k ожидал false; вернул ложь

k == я ожидал ложь; вернул false

6
ответ дан Jevgeni Kiski 10 May 2016 в 19:43
поделиться

Конечно, это не единственный способ - вы можете создать прототип метода (здесь против 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 () абсолютно не достаточно хороши , но метод, который был бы приемлемым, очень сложен из-за проблемы с пробелами, имеющими значение или нет, не говоря уже о методах-синонимах и методах, дающих одинаковый результат при разных реализациях. И проблемы создания прототипов против Object в целом.

21
ответ дан 19 December 2019 в 20:20
поделиться

, если вы хотите явно проверить методы, вы можете использовать методы method.toSource () или method.toString ().

4
ответ дан 19 December 2019 в 20:20
поделиться

Если вы работаете без библиотеки 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
3
ответ дан 19 December 2019 в 20:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: