function similar(needle, haystack, exact){
  if(needle === haystack){
    return true;
  }
  if(needle instanceof Date && haystack instanceof Date){
    return needle.getTime() === haystack.getTime();
  }
  if(!needle || !haystack || (typeof needle !== 'object' && typeof haystack !== 'object')){
    return needle === haystack;
  }
  if(needle === null || needle === undefined || haystack === null || haystack === undefined || needle.prototype !== haystack.prototype){
    return false;
  }
  var keys = Object.keys(needle);
  if(exact && keys.length !== Object.keys(haystack).length){
    return false;
  }
  return keys.every(function(k){
    return similar(needle[k], haystack[k]);
  });
}
function similarIndex(needle, haystack, exact){
  for(var i=0,l=haystack.length; i<l; i++){
    if(similar(needle, haystack[i], exact)){
      return i;
    }
  }
  return -1;
}
var objArray = [{a:1, b:[5, 'wtf'], c:{another:'cool', neat:'not', num:1}, d:'simple string'}, {a:1, b:[5, 'word'], c:{another:'cool', neat:'not', num:1}, d:'simple string'}, {a:1, b:[5, 'word'], c:{another:'cool', neat:'not', num:4}, d:'simple string'}];
var testObj = {a:1, b:[5, 'word'], c:{another:'cool', neat:'not', num:1}, d:'simple string'};
console.log(similarIndex(testObj, objArray, true)); // exact - index is 1 in this case
objArray[1].newProp = 'new value'; // haystack array element 1 gets new property and value
console.log(similarIndex(testObj, objArray, true)); // exact - -1 result here
console.log(similarIndex(testObj, objArray)); // not exact - index 1