fix(filterFilter): correctly handle deep expression objects

Previously, trying to use a deep expression object (i.e. an object whose properties can be objects themselves) did not work correctly. This commit refactors `filterFilter`, making it simpler and adding support for filtering collections of arbitrarily deep objects.

Closes #9698

---
<sub>
BTW, I used "non-IE8" stuff (like `Array.prototype.some/every`) for the sake of conciseness and clarity, so this is not directly back-portable to 1.2.x. If there is interest, I can create a IE8 compatible version (using `for-loops` etc).
</sub>
> What I'm saying is that previously, we did support properties from the prototype chain, so removing support for this would be a breaking change, regardless of whether it was documented or not.

I disagree that _any bug-fix is a breaking change, unless the behaviour was explicitly documented_.
There are behaviours that are obvious/reasonable and therefore expected (even if not explicitly documented).

Taking into account inherited properties of the expression object (but ignoring inherited properties of the items) makes absolutely no sense to me.
E.g.

    Object.prototype.someProp = '123';

    var items = [{test: 'hello'}];
    var expr = {text: 'hell'};
    var filtered = filterFilter(items, expr);

    console.log(filtered.length);   // Prints: 0

This is totally unexpected and a bug if you ask me (even of it is not documented to work otherwise), because both the items and the expression have the same inherited property (yet we only take it into account in the expression object).
So, right now, inherited properties are **neither** supported **nor** documented to be supported. If we want to fix this, we need to decide what to do about it (ignore them or not), document it, implement it and test it. Whatever path we decide to take, it will not be a breaking change (because the feature is not working (or expected to be working) right now.

---
I am not really sure what you mean by _"Since we can't land a breaking change at this point"_ (because I've seen small breaking changes landing :smile:).

---
This whole thing sounds to me a lot like the following scenario, which we have seen enough in the 1.x series imo:
> We have this thing that is broken and we know it is broken.
> Yet, we don't want to introduce a tiny "breaking change" (which is actually a bug-fix), because it will break it's "brokeness".
> So we keep patching it up, until it is so broken that we are sick of it.
> Then, whenever a new issue is brought to light (and they unavoidably will), we complain about the brokeness of the thing.

So, instead of making `filterFilter` on of those _"so broken that makes us sick and will do better in 2.x"_ thing, lets fix its brokeness while it's still a bug-fix :smiley:

--
<sub>
This is just me thinking out loud. I do understand the whole "no breaking changes" reasoning and (although I very much like to break my things) I am very conservative when it comes to breaking other people's things (aka apps).
But when things are broken, then fixing them is not a breaking change (although some apps inevitably have found ways to work-around (and therefore rely) on the previous brokeness of things).
Just m2c...
</sub>