Принудительный выход из из рекурсивной функции

У меня есть объект дерева в котором я хочу найти файл, он может лежать как на каком-то уровне, так и в какой-то папке, если в папке, то я рекурсивно вызываю функцию.

Я хочу вернуть true, если файл найден, но из-за множественной рекурсии значение на выходе меняется.

На первом уровне все нормально выводит, только выше подымаюсь - выдает undefined.

let tree = {
  firstLevelFirstField: {
    secondLevelFirstField: 1,
    secondLevelSecondField: {
      thirdLevelFirstField: 'a2',
      thirdLevelSecondField: {
        fourthLevelFirstField: {
          fifthLevelFirstField: 'a2',
          fifthLevelSecondField: 5,
          fifthLevelThirdField: 'School'
        }
      },
      thirdLevelThirdField: {},
      thirdLevelFourthField: 500
    },
    secondLevelThirdField: {},
    secondLevelFourthField: {
      thirdLevelFirstField: 'JavaScript',
      thirdLevelSecondField: 'margin auto',
      thirdLevelThirdField: '!important is evel'
    },
    secondLevelFifthField: 'Async'
  },
  firstLevelSecondField: 'easy',
  firstLevelThirdField: 123,
  firstLevelFourthField: {
    secondLevelFirstField: 'React.js',
    secondLevelSecondField: {
      thirdLevelFirstField: 42
    }
  }
};


function FindFile(tree, file) {
  for (let key in tree) {
    // значения ключей
    if (typeof(tree[key]) == 'object') {
      FindFile(tree[key], file);
    } else if (tree[key] == file) {
      return true;
    }
  }
}
console.log(FindFile(tree, '500'));


Ответы (2 шт):

Автор решения: Grundy

Проблема в том, что результат рекурсии не возвращается

if (typeof(tree[key]) == 'object') {
  FindFile(tree[key], file);
}

здесь возвращаемое значение теряется.

Так как вызов происходит внутри цикла, если значение найдено на нижнем уровне, цикл надо прервать, и продолжить в противном случае.

Таким образом надо добавить условие

if (FindFile(tree[key], file)) // если нашли на нижнем уровне
  return true;

Пример:

let tree = {
  firstLevelFirstField: {
    secondLevelFirstField: 1,
    secondLevelSecondField: {
      thirdLevelFirstField: 'a2',
      thirdLevelSecondField: {
        fourthLevelFirstField: {
          fifthLevelFirstField: 'a2',
          fifthLevelSecondField: 5,
          fifthLevelThirdField: 'School'
        }
      },
      thirdLevelThirdField: {},
      thirdLevelFourthField: 500
    },
    secondLevelThirdField: {},
    secondLevelFourthField: {
      thirdLevelFirstField: 'JavaScript',
      thirdLevelSecondField: 'margin auto',
      thirdLevelThirdField: '!important is evel'
    },
    secondLevelFifthField: 'Async'
  },
  firstLevelSecondField: 'easy',
  firstLevelThirdField: 123,
  firstLevelFourthField: {
    secondLevelFirstField: 'React.js',
    secondLevelSecondField: {
      thirdLevelFirstField: 42
    }
  }
};


function FindFile(tree, file) {
  for (let key in tree) {
    // значения ключей
    if (typeof(tree[key]) == 'object') {
      if (FindFile(tree[key], file)) return true;
    } else if (tree[key] == file) {
      return true;
    }
  }
}
console.log(FindFile(tree, '500'));

→ Ссылка
Автор решения: 4500zenja

Не совсем изящно, но можно в условии входа в новый слой функции проверять возвращаемое значение — если оно равно true, то тогда нужно прервать выполнение, передав вышестоящему слою true.

let tree = {
  firstLevelFirstField: {
    secondLevelFirstField: 1,
    secondLevelSecondField: {
      thirdLevelFirstField: 'a2',
      thirdLevelSecondField: {
        fourthLevelFirstField: {
          fifthLevelFirstField: 'a2',
          fifthLevelSecondField: 5,
          fifthLevelThirdField: 'School'
        }
      },
      thirdLevelThirdField: {},
      thirdLevelFourthField: 500
    },
    secondLevelThirdField: {},
    secondLevelFourthField: {
      thirdLevelFirstField: 'JavaScript',
      thirdLevelSecondField: 'margin auto',
      thirdLevelThirdField: '!important is evel'
    },
    secondLevelFifthField: 'Async'
  },
  firstLevelSecondField: 'easy',
  firstLevelThirdField: 123,
  firstLevelFourthField: {
    secondLevelFirstField: 'React.js',
    secondLevelSecondField: {
      thirdLevelFirstField: 42
    }
  }
};


function FindFile(tree, file) {
  for (let key in tree) {
    // значения ключей
    if (typeof(tree[key]) === 'object') {
      if (FindFile(tree[key], file)) {  // проверяем, если вышестоящая функция вернула true
          return true                   // то передаём его на слой выше
      }
    } else if (tree[key] == file) {
      return true;
    }
  }
}
console.log(FindFile(tree, '500'));

→ Ссылка