Est-il possible de faire une comparaison superficielle qui ne descendra pas et de comparer le contenu des objets à l'intérieur des objets en Javascript ou lodash? Notez que j'ai vérifié lodash, mais il semble effectuer une comparaison approfondie que je ne veux pas faire.
var a = { x: 1, y: 2}
var b = { x: 1, y: 3}
Existe-t-il un moyen, par exemple, de comparer a
et b
?
function areEqualShallow(a, b) {
for(var key in a) {
if(!(key in b) || a[key] !== b[key]) {
return false;
}
}
for(var key in b) {
if(!(key in a) || a[key] !== b[key]) {
return false;
}
}
return true;
}
Remarques:
Puisque c'est peu profond, areEqualShallow({a:{}}, {a:{}})
est faux.
areEqualShallow({a:undefined}, {})
est faux.
Cela inclut toutes les propriétés du prototype.
Cela utilise la comparaison ===
. Je suppose que c'est ce que vous voulez. NaN === NaN
Est un cas qui peut donner des résultats inattendus. Si ===
N'est pas ce que vous voulez, remplacez-le par la comparaison que vous voulez.
EDIT: Si les mêmes clés sont dans chaque objet, alors
function areEqualShallow(a, b) {
for(var key in a) {
if(a[key] !== b[key]) {
return false;
}
}
return true;
}
Approche ES6 simple:
const shallowCompare = (obj1, obj2) =>
Object.keys(obj1).length === Object.keys(obj2).length &&
Object.keys(obj1).every(key => obj1[key] === obj2[key]);
Ici, j'ai ajouté que la vérification de l'égalité du montant des clés d'objet pour la comparaison suivante devrait échouer (un cas important qui n'est généralement pas pris en compte):
shallowCompare({ x: 1, y: 3}, { x: 1, y: 3, a: 1}); // false
mise à jour 2019. Selon le commentaire d'Andrew Rasmussen, nous devons également prendre en compte le cas undefined
. Le problème avec l'approche précédente est que la comparaison suivante renvoie true
:
({ foo: undefined })['foo'] === ({ bar: undefined })['foo'] // true
Un contrôle explicite de l'existence des clés est donc nécessaire. Et cela pourrait être fait avec hasOwnProperty
:
const shallowCompare = (obj1, obj2) =>
Object.keys(obj1).length === Object.keys(obj2).length &&
Object.keys(obj1).every(key =>
obj2.hasOwnProperty(key) && obj1[key] === obj2[key]
);
en gardant à l'esprit que ce n'est que pour les chaînes peu profondes et uniquement pour les chaînes et les nombres
function equals(obj1, obj2) {
return Object.keys(obj1)
.concat(Object.keys(obj2))
.every(key => {
return obj1[key] === obj2[key];
});
}
Ceci est retiré de fbjs :
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @typechecks
*
*/
/*eslint-disable no-self-compare */
'use strict';
var hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* inlined Object.is polyfill to avoid requiring consumers ship their own
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
*/
function is(x, y) {
// SameValue algorithm
if (x === y) {
// Steps 1-5, 7-10
// Steps 6.b-6.e: +0 != -0
return x !== 0 || 1 / x === 1 / y;
} else {
// Step 6.a: NaN == NaN
return x !== x && y !== y;
}
}
/**
* Performs equality by iterating through keys on an object and returning false
* when any key has values which are not strictly equal between the arguments.
* Returns true when the values of all keys are strictly equal.
*/
function shallowEqual(objA, objB) {
if (is(objA, objB)) {
return true;
}
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
return false;
}
var keysA = Object.keys(objA);
var keysB = Object.keys(objB);
if (keysA.length !== keysB.length) {
return false;
}
// Test for A's keys different from B.
for (var i = 0; i < keysA.length; i++) {
if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
return false;
}
}
return true;
}
module.exports = shallowEqual;
Je recommande de le copier dans votre propre projet si vous avez besoin de l'utiliser, car leur README indique clairement qu'ils peuvent supprimer ou modifier ce code et tout autre code dans la bibliothèque sans avertissement.
La solution de Paul Draper peut être optimisée en supprimant la comparaison lors de la deuxième passe.
function areEqualShallow(a, b) {
for (let key in a) {
if (!(key in b) || a[key] !== b[key]) {
return false;
}
}
for (let key in b) {
if (!(key in a)) {
return false;
}
}
return true;
}
Pour faire une comparaison "superficielle" où les propriétés héritées doivent être ignorées et NaN
doit être égal à NaN
, ce qui suit doit faire le travail. Il vérifie que chaque objet a les mêmes propriétés et que les valeurs sont ===
ou les deux NaN
:
function checkProperties(a, b) {
var equal = true;
// For each property of a
for (var p in a) {
// Check that it's an own property
if (a.hasOwnProperty(p)) {
// Check that b has a same named own property and that the values
// are === or both are NaN
if (!b.hasOwnProperty(p) ||
(b[p] !== a[p] && !(typeof b[p] == 'number' && typeof a[p] == 'number' && isNaN(b[p] && isNaN(a[p]))))) {
// If not, set equal to false
equal = false;
}
}
// If equal is false, stop processing properties
if (!equal) break;
}
return equal;
}
Utiliser des fonctionnalités récentes comme Object.keys pour obtenir ses propres propriétés, puis
function checkProperties(a, b) {
return Object.keys(a).every(function(p) {
return b.hasOwnProperty(p) &&
(b[p] == a[p] || (typeof a[p] == 'number' && typeof b[p] == 'number' && isNaN(b[p]) && isNaN(a[p])));
});
}
// Compare a to b and b to a
function areEqualShallow(a, b) {
return checkProperties(a, b) && checkProperties(b, a);
}
// Minimal testing
var a = {foo:'a', bar:2};
var b = {foo:'a', bar:2};
var c = {foo:'c', bar:2};
var d = {foo:'a', bar:2, fum:0};
console.log('a equal to b? ' + areEqualShallow(a,b)); // true
console.log('a equal to c? ' + areEqualShallow(a,c)); // false
console.log('a equal to d? ' + areEqualShallow(a,d)); // false
Avec des fonctionnalités plus récentes, la fonction checkProperties peut être quelque peu simplifiée:
var a = { x: 1, y: 2}
var b = { x: 1, y: 3}
function shalComp (obj1, obj2) {
var verdict = true;
for (var key in obj1) {
if (obj2[key] != obj1[key]) {
verdict = false;
}
}
return verdict;
}