For the same reason I didn't want to make `findByString`, I also don't want to have a special method for something that's better handled via parameterization. Instead of creating a second "almost the same" operation, there should be an abstraction for creating a contacts filter object with parameters that are backed by reasonable defaults:

```js

/**
 * Contacts.Filter(filterValue [, filterBy, filterOp ])
 *
 * Construct contact filter object instances
 *
 * @param {String} (Required) filterValue
 *                            Value for contact field value matching.
 *
 * @param {Array}  (Optional) filterBy
 *                            Field names of contact record to look in.
 *                            Defaults to ['tel', 'givenName', 'familyName'].
 *
 * @param {String} (Optional) filterOp
 *                            Matching operation directive
 *                            One of: { 'contains', 'equals' }
 *                            Defaults to 'equals'
 *
 */

Contacts.Filter = function(filterValue, filterBy, filterOp) {
  if (!(this instanceof Contacts.Filter)) {
    return new Contacts.Filter(filterValue, filterBy, filterOp);
  }
  this.filterValue = filterValue || '';
  this.filterBy = filterBy || ['tel', 'givenName', 'familyName'];
  this.filterOp = filterOp || 'contains';
};


// Examples
//
// For the number 'equals' case:
Contacts.findBy(Contacts.Filter('999', ['tel'], 'equals'), function() {
  /*

  [Contacts.Filter] {
    filterValue: '999',
    filterBy: ['tel'],
    filterOp: 'equals'
  }
  */
  ...
});



// For the number or name contains case:
Contacts.findBy(Contacts.Filter('jane'), function() {
  /*

  [Contacts.Filter] {
    filterValue: 'jane',
    filterBy: ['tel', 'givenName', 'familyName'],
    filterOp: 'contains'
  }
  */
  ...
});


```


This would also replace the `Contacts.findByString` call sites