使用lodash的isEqual()排除一些属性

时间:2016-06-20 12:46:18

标签: javascript lodash

我正在使用_.isEqual来比较2个对象数组(例如:每个对象有10个属性),并且它工作正常。

现在有2个属性(创建和删除),我不需要成为比较的一部分。

示例:

var obj1 = {name: "James", age: 17, creation: "13-02-2016", deletion: "13-04-2016"}
var obj2 = {name: "Maria", age: 17, creation: "13-02-2016", deletion: "13-04-2016"}

// lodash method...
_.isEqual(firstArray, secondArray)

6 个答案:

答案 0 :(得分:58)

您可以使用omit()删除对象中的特定属性。

var result = _.isEqual(
  _.omit(obj1, ['creation', 'deletion']),
  _.omit(obj2, ['creation', 'deletion'])
);



var obj1 = {
  name: "James",
  age: 17,
  creation: "13-02-2016",
  deletion: "13-04-2016"
};

var obj2 = {
  name: "Maria",
  age: 17,
  creation: "13-02-2016",
  deletion: "13-04-2016"
};

var result = _.isEqual(
  _.omit(obj1, ['creation', 'deletion']),
  _.omit(obj2, ['creation', 'deletion'])
);

console.log(result);

<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:10)

@ ryeballar的答案对于大型对象来说并不是很好,因为每次进行比较时都会创建每个对象的深层副本。

最好使用isEqualWith。例如,要忽略“创建”和“删除”属性中的差异:

var result = _.isEqualWith(obj1, obj2, (value1, value2, key) => {
    return key === "creation" || key === "deletion" ? true : undefined;
});

EDIT(评论中指出的重要警告):如果对象具有不同数量的键,则isEqualWith会认为它们不同,无论您的自定义程序执行什么操作。因此,如果您想忽略可选属性,不要使用此方法。请考虑使用_.isMatch()_.isMatchWith()或@ ryeballar的_.omit()方法。

请注意,如果您是为ES5及更早版本编写的,则必须使用函数语法(() => {)替换箭头语法(function() {

答案 2 :(得分:3)

你可以map将你的数组放入&#34;清理&#34;数组,然后比较那些。

// Create a function, to do some cleaning of the objects.
var clean = function(obj) {
    return {name: obj.name, age: obj.age};
};

// Create two new arrays, which are mapped, 'cleaned' copies of the original arrays.
var array1 = firstArray.map(clean);
var array2 = secondArray.map(clean);

// Compare the new arrays.
_.isEqual(array1, array2);

如果对象期望任何新属性,则需要更新clean函数。可以对其进行编辑,以便它删除两个不需要的属性。

答案 3 :(得分:2)

_.omit创建对象的深层副本。如果您只需要排除根道具,则最好使用破坏性任务创建浅副本:

const x = { a: 4, b: [1, 2], c: 'foo' }
const y = { a: 4, b: [1, 2], c: 'bar' }

const { c: xC, ...xWithoutC } = x
const { c: yC, ...yWithoutC } = y

_.isEqual(xWithoutC, yWithoutC) // true
xWithoutC.b === x.b             // true, would be false if you use _.omit

最佳方法是根本不创建副本(TypeScript):

function deepEqual(
  x?: object | null,
  y?: object | null,
  ignoreRootProps?: Set<string>
) {
  if (x == null || y == null) return x === y

  const keys = Object.keys(x)
  if (!_.isEqual(keys, Object.keys(y)) return false

  for (let key of keys) {
    if (ignoreRootProps && ignoreRootProps.has(key)) continue
    if (!_.isEqual(x[key], y[key])) return false
  }
  return true
}

答案 4 :(得分:0)

我看到两个选项。

1)为每个不包含创建或日期的对象制作第二个副本。

2)遍历所有属性,假设您确定它们都具有相同的属性,请尝试这样的事情。

var x ={}
var y ={}
for (var property in x) {
if(property!="creation" || property!="deletion"){
if (x.hasOwnProperty(property)) {
        compare(x[property], y[property])
    }
}
}

其中compare()是一些简单的字符串或对象比较。如果您确定某个或两个对象上的属性,则可以进一步简化此代码,但这在大多数情况下都适用。

答案 5 :(得分:0)

我的最终解决方案需要完全比较,而忽略了可选属性,因此上述解决方案无法正常工作。

在与isEqual比较之前,我使用了浅表克隆从每个对象中删除了我想忽略的键:

const equalIgnoring = (newItems, originalItems) => newItems.length === originalItems.length
    && newItems.every((newItem, index) => {
        const rest1 = { ...newItem };
        delete rest1.creation;
        delete rest1.deletion;
        const rest2 = { ...originalItems[index] };
        delete rest2.creation;
        delete rest2.deletion;
        return isEqual(rest1, rest2);
    });

如果您要检查数组中每个项目的子集,都可以:

const equalIgnoringExtraKeys = (fullObjs, partialObjs) => 
    fullObjs.length === partialObjs.length
    && fullObjs.every((fullObj, index) => isMatch(fullObj, partialObjs[index]));

如果您还想忽略特定属性并检查子集:

const subsetIgnoringKeys = (fullObjs, partialObjs) => 
    fullObjs.length === partialObjs.length
    && fullObjs.every((fullObj, index) => isMatchWith(
        fullObj,
        partialObjs[index],
        (objValue, srcValue, key, object, source) => {
            if (["creation", "deletion"].includes(key)) {
                return true;
            }
            return undefined;
        }
    ));