2

LoDash (2.2.1) _.find() and _.where() is working with dynamic object array like

[{
  id: 1,
  name: 'Some name',
  event: {id: 101, text: 'Event text'}
}]

but not with typed object array (with 2 level deep) like

[new Person({
  id: 1,
  name: 'Some name',
  event: {id: 101, text: 'Event text'}
})]
// Event will be converted to Event type

Please see this JSFiddle.

Advice?

SM Adnan
  • 555
  • 2
  • 10
  • @Cerbrus I don't think this is an exact duplicate. That question is about nesting levels, this is not. – Alexis King Sep 24 '14 at 09:01
  • + In that question _.find was working fine with 2 level depth. But here it's creating problem. + Here the main issue is dynamic object vs typed object – SM Adnan Sep 24 '14 at 09:04

1 Answers1

3

The problem

The problem is that inside your typed array the type of event properties of Person objects is Event but as a parameter to _.find is object. Let me explain:

Lodash takes an object that you pass to _.find as a second parameter (let's call it target) and tries to compare properties of this object with the original one (that is passed as the 1st parameter, let's call it source). So in case of typed array:

  • the source object has type Person (that's OK) and it has 3 properties: id (type int), name (type string) and event (type Event)
  • the target object has 2 properties: name (type string - that's OK, as in the source object property name also has type string) and event (type object - and here's the problem!)

Take a look inside baseIsEqual method inside lodash: it has lots of different checks. Some of them look not pretty good but it's a victim for the performance (see more in comments started with exit early for ...). And inside one of these checks there's a code for getting constructors and comparing them

var ctorA = !support.argsObject && isArguments(a) ? Object : a.constructor,
    ctorB = !support.argsObject && isArguments(b) ? Object : b.constructor;

if (ctorA != ctorB && !(
    isFunction(ctorA) && ctorA instanceof ctorA &&
    isFunction(ctorB) && ctorB instanceof ctorB
    )) {
        return false;
}

And note the comment // non Object object instances with different constructors are not equal. It that case the constructor of the source object's event property is the Event class constructor but the constructor of target object's event property - is function Object() { [native code] } as it was created as a literal objects.

So, how to fix it?

Easy! You can pass to _.find predicate as a second parameter. So the code should be:

var typedResult1   = _.find(typedArray, function(p) {
    return p.name === "Adnan" && p.event && p.event.id === 101;
});

jsFiddle

Kiril
  • 2,935
  • 1
  • 33
  • 41
  • The solution you have proposed is a workaround, but we can do this with native JavaScript, LoDash is not required. Anyway, I have created my own function to achieve the same :), finally thanks a lot for your time on this issue. – SM Adnan Oct 02 '14 at 06:01