Jak napsat funkci, která hledá konkrétní pár klíč/hodnota na objektu a volat tuto funkci rekurzivně, aby procházela objekty libovolné hloubky.
Začínáme
Pro tento tutoriál vytvoříme jednoduchý projekt Node.js s jedním souborem. V počítači vyberte vhodné umístění souboru (např. složku projektů) a vytvořte soubor s názvem index.js
.
Dále se ujistěte, že jste do počítače nainstalovali Node.js. Zatímco kód, který píšeme, ne závisí na tom, aby fungoval Node.js, budeme ho potřebovat ke spuštění nebo spuštění kódu, který napíšeme do index.js
.
Jakmile vytvoříte svůj soubor a nainstalujete Node.js, jsme připraveni začít.
Vytvoření funkce pro spárování objektů podle klíče a hodnoty
Snadný způsob, jak pochopit pojem rekurze, je představit si točité schodiště v domě. Abyste mohli přejít z horní části schodiště dolů, musíte sejít po jednom schodu.
I když to děláte automaticky, technicky máte ve svém mozku „funkci“, která vám říká, jak sejít krok po kroku, dokud nedosáhnete dna. Tuto „funkci“ voláte pro každý schod na schodišti, dokud už žádné schody nebudou. Když jdete dolů, říkáte "funkci", aby se znovu zavolala, pokud je krok po aktuálním kroku.
Takto funguje rekurze v JavaScriptu (nebo v jakémkoli programovacím jazyce). Napíšete funkci, která provede úlohu a necháte tuto funkci zavolat znovu, pokud nesplnila nějaký požadavek – například nalezení vnořené hodnoty nebo dosažení konce seznamu.
Pro tento tutoriál napíšeme funkci, která se zaměřuje na první:nalezení vnořeného objektu. Přesněji řečeno, chceme napsat rekurzivní funkci, která najde vnořený objekt obsahující konkrétní klíč s konkrétní hodnotou.
Nejprve vytvoříme naši základní funkci a vysvětlíme, o co jde:
/index.js
const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
// We'll implement our function here...
};
Naše funkce bude mít tři argumenty:object
k procházení keyToMatch
v tomto objektu a valueToMatch
v rámci tohoto objektu.
/index.js
const isObject = (value) => {
return !!(value && typeof value === "object" && !Array.isArray(value));
};
const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
if (isObject(object)) {
// We'll work on finding our nested object here...
}
return null;
};
Dále, abychom se vyhnuli chybám při běhu, v těle našeho findNestedObject
funkci, přidáme if
příkaz s voláním nové funkce, kterou jsme přidali výše isObject()
, předáním object
argument, který byl předán do findNestedObject
.
Podívejte se na isObject()
, chceme si být jisti, že objekt, kterým procházíme, je ve skutečnosti objekt. Abychom to zjistili, musíme ověřit, že jste předali value
není null nebo nedefinováno, má typeof
"objekt" a není pole. Ten poslední může vypadat divně. Musíme udělat !Array.isArray()
protože v JavaScriptu Array
s mají typeof
"object" (což znamená, že naše předchozí typeof value === "object"
test může být "oklamán" předávaným polem).
Za předpokladu, že isObject()
vrátí true
pro hodnotu, kterou jsme jí předali, můžeme začít objekt procházet. Pokud ne, jako záložní řešení z našeho findNestedObject()
vrátíme null
na znamení, že neudělali najít shodu.
/index.js
const isObject = (value) => {
return !!(value && typeof value === "object" && !Array.isArray(value));
};
const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
if (isObject(object)) {
const entries = Object.entries(object);
for (let i = 0; i < entries.length; i += 1) {
const [treeKey, treeValue] = entries[i];
if (treeKey === keyToMatch && treeValue === valueToMatch) {
return object;
}
}
}
return null;
};
Když přidáme nějakou složitost, chceme nyní začít procházet naším objektem. „Přejížděním“ rozumíme smyčkování přes každý pár klíč/hodnota na object
předán na findNestedObject()
.
K provedení této smyčky nejprve zavoláme Object.entries()
předáním našeho object
. To nám vrátí pole polí, kde každé pole obsahuje key
páru klíč/hodnota, který je v současné době ve smyčce zacyklen jako první prvek a value
páru klíč/hodnota, který je v současné době zacyklen jako druhý prvek. Takhle:
const example = {
first: 'thing',
second: 'stuff',
third: 'value',
};
Object.entries(example);
[
['first', 'thing'],
['second', 'stuff'],
['third', 'value']
]
Dále s naším polem párů klíč/hodnota (položky) přidáme for
smyčka pro iteraci přes pole. Zde i
se bude rovnat indexu aktuálního páru klíč/hodnota, přes který procházíme smyčkou. Chceme to udělat, dokud neprovedeme smyčku přes všechny celky, takže řekneme „spustit tuto smyčku, zatímco i < entries.length
a pro každou iteraci a 1
na aktuální index i
."
Uvnitř for
smyčky, používáme destrukci pole JavaScript pro přístup k aktuálnímu poli párů klíč/hodnota (označené entries[i]
), přičemž každému přiřadíte proměnnou. Zde přiřadíme první prvek proměnné objectKey
a druhý prvek do proměnné objectValue
.
Pamatujte:naším cílem je najít objekt podle předané keyToMatch
a valueToMatch
. Abychom našli shodu, musíme zkontrolovat každý klíč a hodnotu na našem object
abychom viděli, jestli se shodují. Zde, za předpokladu, že najdeme shodu, vrátíme object
protože splňuje požadavek mít keyToMatch
a valueToMatch
.
Přidání rekurze k procházení objektů libovolné hloubky
Nyní k té zábavnější části. Právě teď může naše funkce provádět smyčku pouze přes jednoúrovňový hloubkový objekt. To je skvělé, ale nezapomeňte, že chceme hledat vnořené objekt. Protože nevíme, kde by tento objekt mohl být ve „stromu“ (přezdívka, kterou občas uslyšíte pro objekt vnořených objektů), musíme být schopni „pokračovat“, pokud jedna z hodnot v klíči/ pár hodnot je sám o sobě objektem.
Zde přichází na řadu naše rekurze.
/index.js
const isObject = (value) => {
return !!(value && typeof value === "object" && !Array.isArray(value));
};
const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
if (isObject(object)) {
const entries = Object.entries(object);
for (let i = 0; i < entries.length; i += 1) {
const [objectKey, objectValue] = entries[i];
if (objectKey === keyToMatch && objectValue === valueToMatch) {
return object;
}
if (isObject(objectValue)) {
const child = findNestedObject(objectValue, keyToMatch, valueToMatch);
if (child !== null) {
return child;
}
}
}
}
return null;
};
Vzpomeňte si na naši analogii se schodištěm z dřívějška. V tuto chvíli jsme sešli pouze o jeden krok. Abychom mohli přejít k dalšímu kroku, musíme naší funkci říci, aby se znovu zavolala.
V tomto případě víme, že existuje další „krok“ nebo objekt, který je třeba překonat, pokud projdete objectValue
na isObject()
funkce, kterou jsme nastavili dříve, vrací true
. Pokud ano , to znamená, že musíme zkontrolovat, zda to objekt obsahuje keyToMatch
a valueToMatch
hledáme.
Abychom tímto objektem prošli, rekurzivně (to znamená, že znovu zavoláme funkci, ve které se právě nacházíme), předáme objectValue
spolu s původním keyToMatch
a keyToValue
(to, co hledáme, se nezměnilo, jen objekt, na který se chceme podívat).
Pokud naše rekurzivní volání najde shodu (což znamená naše rekurzivní volání na findNestedObject()
není vrátí null
), vrátíme tento objekt child
. Za předpokladu, že naše rekurzivní volání findNestedObject()
nevrátil zápas, náš průjezd by se zastavil. Pokud by naše dítě samo mělo vnořené objekty (podle naší analogie, další "krok" k sestupu), opět bychom zavolali findNestedObject()
.
Protože je tento kód rekurzivní, poběží, dokud buď nenajde odpovídající objekt, nebo nevyčerpá dostupné vnořené objekty pro hledání.
Nyní na zkoušku. Zkusme najít objekt v tomto stromu s name
pole rovné "Tady dole!"
/index.js
const isObject = (value) => {
return !!(value && typeof value === "object" && !Array.isArray(value));
};
const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
if (isObject(object)) {
const entries = Object.entries(object);
for (let i = 0; i < entries.length; i += 1) {
const [objectKey, objectValue] = entries[i];
if (objectKey === keyToMatch && objectValue === valueToMatch) {
return object;
}
if (isObject(objectValue)) {
const child = findNestedObject(objectValue, keyToMatch, valueToMatch);
if (child !== null) {
return child;
}
}
}
}
return null;
};
const staircase = {
step: 5,
nextStep: {
step: 4,
nextStep: {
step: 3,
nextStep: {
step: 2,
nextStep: {
name: "Down here!",
step: 1,
},
},
},
},
};
const match = findNestedObject(staircase, "name", "Down here!");
console.log(match);
// { name: "Down here!", step: 1 }
const match2 = findNestedObject(staircase, "step", 3);
console.log(match2);
// { step: 3, nextStep: { step: 2, nextStep: { name: "Down here!", step: 1 } } }
Zde je rychlá ukázka tohoto běhu v reálném čase:
Zabalení
V tomto tutoriálu jsme se naučili, jak rekurzivně procházet objektem pomocí JavaScriptu. Naučili jsme se, jak vytvořit základní funkci, která byla schopna procházet klíči objektu, který jsme jí předali, a hledat odpovídající pár klíč a hodnota. Potom jsme se naučili, jak tuto funkci používat rekurzivně , volá jej zevnitř, pokud hodnota páru klíč/hodnota, přes který jsme aktuálně procházeli, byl objekt.