Ответ 1
Код ниже добавляет что-то вроде того, что вы ищете для объекта консоли, как
console.logSearchingForValue
Поиск по ширине, совпадение по эквивалентному значению "JSON", правильное обращение с NaNs, возвращение нескольких местоположений и выдача числовых индексных выражений, не цитируемых, остаются в качестве упражнений для читателя.:)
Это уже очень легко заменить в разных определениях равенства.
var searchHaystack = function(haystack, needle, path, equalityFn, visited) {
if(typeof haystack != "object") {
console.warn("non-object haystack at " + path.join("."));
}
if(visited.has(haystack))
return [false, null];
for(var key in haystack) {
if(!haystack.hasOwnProperty(key))
continue;
if(equalityFn(needle, haystack[key])) {
path.push(key);
return [true, path];
}
visited.add(haystack);
if(typeof haystack[key] == "object") {
var pCopy = path.slice();
pCopy.push(key);
var deeper = searchHaystack(haystack[key], needle, pCopy, equalityFn, visited);
}
}
return [false, null];
}
var pathToIndexExpression = function(path) {
var prefix = path[0];
path = path.slice(1);
for(var i = 0; i < path.length; i++) {
if(typeof path[i] == "string")
path[i] = "\"" + path[i] + "\"";
}
return prefix + "[" + path.join("][") + "]"
}
console.logSearchingForValue = function(haystack, needle) {
this.log("Searching");
this.log(haystack);
this.log("for");
this.log(needle);
var visited = new Set();
var strictEquals = function(a,b) { return a === b; };
var result = searchHaystack(haystack, needle, ["<haystack>"], strictEquals, visited);
if(result[0]) {
this.log("Found it!");
this.log(pathToIndexExpression(result[1]));
}
else {
this.log("didn't find it");
}
}