Comparação profunda de objects / arrays

Duplicar Possível:
Como você determina a igualdade para dois objects JavaScript?
Comparação de objects em JavaScript

Se eu tiver dois arrays ou objects e quiser compará-los, como

object1 = [ { shoes: [ 'loafer', 'penny' ] }, { beers: [ 'budweiser', 'busch' ] } ] object2 = [ { shoes: [ 'loafer', 'penny' ] }, { beers: [ 'budweiser', 'busch' ] } ] object1 == object2 // false 

isso pode ser irritante se você está recebendo uma resposta de um servidor e tentando ver se ele foi alterado

Atualizar:
Em resposta aos comentários e preocupações em torno da sugestão original (comparando duas strings JSON), você poderia usar esta function:

 function compareObjects(o, p) { var i, keysO = Object.keys(o).sort(), keysP = Object.keys(p).sort(); if (keysO.length !== keysP.length) return false;//not the same nr of keys if (keysO.join('') !== keysP.join('')) return false;//different keys for (i=0;i 

Mas, em muitos casos, não precisa ser tão difícil:

 JSON.stringify(object1) === JSON.stringify(object2); 

Se os objects stringificados forem iguais, seus valores são iguais.
Pelo bem da integralidade: o JSON simplesmente ignora funções (bem, remove todas elas juntas). Significa representar dados , não funcionalidade .
A tentativa de comparar dois objects que contêm apenas funções resultará em true :

 JSON.stringify({foo: function(){return 1;}}) === JSON.stringify({foo: function(){ return -1;}}); //evaulutes to: '{}' === '{}' //is true, of course 

Para uma comparação profunda de objects / funções, você terá que procurar bibliotecas ou escrever sua própria function e superar o fato de que objects JS são todas referências, então, ao comparar o1 === ob2 ele só retornará verdadeiro se ambos as variables ​​apontam para o mesmo object ...

Como @aj apontou no comentário:

 JSON.stringify({a: 1, b: 2}) === JSON.stringify({b: 2, a: 1}); 

é false , pois ambas as chamadas stringify produzem "{"a":1,"b":2}" e "{"b":2,"a":1}" respectivamente. Quanto ao motivo, é preciso entender os componentes internos do motor V8 do chrome. Eu não sou um especialista, e sem entrar em muitos detalhes, aqui está o que tudo se resume a:

Cada object que é criado e cada vez que ele é modificado, o V8 cria uma nova class de C ++ oculta (tipo de). Se o object X tiver uma propriedade a e outro tiver a mesma propriedade, esses dois objects JS referenciarão uma class oculta que herda de uma class oculta compartilhada que define essa propriedade a . Se dois objects compartilharem as mesmas propriedades básicas, todos referenciarão as mesmas classs ocultas, e JSON.stringify funcionará exatamente da mesma maneira nos dois objects. Isso é um dado (Mais detalhes sobre internals do V8 aqui , se você estiver interessado).

No entanto, no exemplo apontado por aj, os dois objects são rigidamente diferenciados. Por quê? Bem, simplesmente, esses objects nunca existem ao mesmo tempo:

 JSON.stringify({a: 1, b: 2}) 

Esta é uma chamada de function, uma expressão que precisa ser resolvida para o valor resultante antes de poder ser comparada ao operando direito. O segundo literal de object ainda não está na tabela.
O object é estendido e a exorcisão é resolvida para uma constante de cadeia. O literal do object não está sendo referenciado em lugar algum e está marcado para garbage collection.
Depois disso, o operando à direita (a JSON.stringify({b: 2, a: 1}) ) recebe o mesmo tratamento.

Tudo bem e elegante, mas o que também precisa ser levado em consideração é que os mecanismos JS agora são muito mais sofisticados do que costumavam ser. Novamente, não sou especialista em V8, mas acho plausível que o snippet de aj esteja sendo altamente otimizado, pois o código é otimizado para:

 "{"b":2,"a":1}" === "{"a":1,"b":2}" 

Essencialmente omitindo o JSON.stringify chama todos juntos, e apenas adicionando aspas nos lugares certos. Isto é, afinal, muito mais eficiente.

Como um sublinhado mixin:

no café-script:

 _.mixin deepEquals: (ar1, ar2) -> # typeofs should match return false unless (_.isArray(ar1) and _.isArray(ar2)) or (_.isObject(ar1) and _.isObject(ar2)) #lengths should match return false if ar1.length != ar2.length still_matches = true _fail = -> still_matches = false _.each ar1, (prop1, n) => prop2 = ar2[n] return if prop1 == prop2 _fail() unless _.deepEquals prop1, prop2 return still_matches 

E em javascript:

 _.mixin({ deepEquals: function(ar1, ar2) { var still_matches, _fail, _this = this; if (!((_.isArray(ar1) && _.isArray(ar2)) || (_.isObject(ar1) && _.isObject(ar2)))) { return false; } if (ar1.length !== ar2.length) { return false; } still_matches = true; _fail = function() { still_matches = false; }; _.each(ar1, function(prop1, n) { var prop2; prop2 = ar2[n]; if (prop1 !== prop2 && !_.deepEquals(prop1, prop2)) { _fail(); } }); return still_matches; } });