Мне кажется, что код второго элемента в items никогда не достигается в цикле for.
Как исправить этот метод?
class Item {
items: Item[] = [];
constructor(public id: string) {}
}
function getItembyIdRecursively(id: string, items: Item[]): Item | undefined {
for (const item of items) {
if (item.id === id) {
return item;
} else {
return getItembyIdRecursively(id, item.items);
}
}
return undefined;
}
const item1 = new Item("1");
const item2 = new Item("2");
item1.items.push(new Item("1.2"));
const items = [item1, item2];
const foundItem = getItembyIdRecursively("2", items);
console.info(foundItem.id);
Образец репродукции вы можете найти здесь:
Итак, проблема в том, что вы безоговорочно возвращаете результат рекурсивного вызова; вам следует проверить, есть ли это undefined, и не возвращать его, если да. Посмотрите ссылку на игровую площадку, которая теперь работает так, как вы хотите. Это полностью решает вопрос? Если да, то я напишу ответ; если нет, то что мне не хватает?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Проблема в вашем операторе else: вы возвращаете результат во всех случаях, даже если это undefined. По сути, поскольку у первого Item есть дочерние элементы, вы возвращаете результат поиска в его дочерних элементах, а поскольку идентификатор не совпадает, вы получаете undefined.
function getItembyIdRecursively(id: string, items: Item[]) : Item | undefined
{
for(const item of items)
{
if (item.id === id)
{
return item;
}
else
{
const elem = getItembyIdRecursively(id, item.items);
if (elem) {
return elem;
}
}
}
return undefined;
}
Это то же самое, что и это.
function getItembyIdRecursively(id: string, items: Item[]) : Item | undefined
{
for(const item of items)
{
if (item.id === id) return item;
const elem = getItembyIdRecursively(id, item.items);
if (elem !== undefined) return elem;
}
return undefined;
}
генераторы
Я думаю, что генераторы предлагают естественный способ выражения функций поиска или обхода. Мы видим, что генератору не требуется дополнительная проверка if, прежде чем продолжить yield*. Еще одним преимуществом является то, что потребителю всегда гарантирована ценность.
function getItem(id: string, items: Item[]): undefined | Item {
function* find(items: Item[]): Generator<Item> {
for (const item of items) {
if (item.id == id) yield item
yield* find(item.items) // unconditional
}
}
for (const match of find(items))
return match // unconditional
}
class Item {
items: Item[]
constructor(
public id: string,
items?: Item[],
) {
this.items = items ?? []
}
}
const example = [
new Item("A", [
new Item("B", [new Item("C"), new Item("D", [new Item("E")])]),
new Item("F"),
]),
]
Запустите этот пример на игровой площадке для машинописных текстов
console.info(getItem("D", example)) // Item: { id: "D", items: [ Item: { id: "E", items: [] } ] }
console.info(getItem("X", example)) // undefined
общая находка
Вместо того, чтобы встраивать генератор в функцию getItem, мы можем определить find как отдельную функцию, независимую от типа Item —
function* find<T>(
values: Iterable<T>,
matchFn: (value: T) => boolean,
recurFn?: (value: T) => Iterable<T>,
): Generator<T> {
for (const value of values) {
if (matchFn(value)) yield value
if (recurFn) yield* find(recurFn(value), matchFn, recurFn)
}
}
Теперь find можно использовать повторно везде, где нам нужна эта функциональность, например getItem -
function getItem(id: string, items: Item[]): undefined | Item {
for (const match of find( // find..
items, // iterable
i => i.id == id, // match
i => i.items, // recur
))
return match // unconditional
}
Запустите этот пример на игровой площадке для машинописных текстов
console.info(getItem("D", example)) // Item: { id: "D", items: [ Item: { id: "E", items: [] } ] }
console.info(getItem("X", example)) // undefined
удобство и контроль: $0,99
Генераторы дают нам всевозможную мощность и гибкость. getItem возвращает только первый результат, что немедленно завершает работу генератора и прекращает сканирование других элементов. С небольшим изменением мы могли бы написать getItems, который возвращает все результаты:
function getItems(ids: string[], items: Item[]): Item[] {
return Array.from(find( // unconditional
items,
i => ids.includes(i.id),
i => i.items,
))
}
Запустите этот пример на игровой площадке для машинописных текстов
console.info(getItems(["E", "F"], example)) // [ Item: { id: "E" }, Item: { id: "F" } ]
console.info(getItems(["X"], example)) // []
Пройдитесь по коду. Что будет возвращено, скажем, когда метод запишет один раз? Что возвращает самый верхний вызов, если рекурсивный вызов возвращает значение?