最初のステートメントは関数定義です。
var walk_the_DOM = function walk(node, func) {
...
};
これにより、 に機能が割り当てられwalk_the_DOM
ます。node
この関数は、との 2 つのパラメータを取りますfunc
。node
は作業対象のノードで、func
は適用対象の機能ですnode
。
関数の最初の行はfunc(node);
. これは基本的に、渡された関数を に適用していることを意味しますnode
。たとえば、次のように呼び出した場合walk_the_DOM
:
walk_the_DOM(root, function(node) {
console.log(node);
});
あなたは電話しているでしょう
function(node) {
console.log(node);
}
ツリー内のすべてのノードを出力する効果として、すべてのノードで。
次の行node = node.firstChild;
は基本的に、node
を最初の子に再割り当てします。これを行う必要があるのは、現在のノードの各子を調べる必要があるためです。もちろん、それらの子の子も確認する必要がありますが、その部分については後で説明します。
これでwhile
ループに入ります。このwhile
ループの条件は just です。これは、が定義されていないか未定義であるwhile(node)
限り、ループが実行されることを意味します。前のステートメントでは、 を行いました。現在のノードに子がない場合はどうなりますか? その後は null になるため、ループには入りません。そこから外れて関数を終了します (この部分を覚えておいてください。現在のノードに子がない場合は関数を終了します。これは、再帰関数の停止条件として知られています)。node
null
node = node.firstChild
node.firstChild
ループ内で、while
再帰呼び出しを行います: walk(node, func);
. ここで起こっていることは一瞬無視して、次の行に進みましょう: node = node.nextSibling;
. ここでは、ノードの次の兄弟を変数に割り当てていますnode
。実際には、このノードの兄弟を繰り返し処理しています。ノードに他の兄弟がない場合 (つまり、親ノードに子が 1 つしかない場合) はどうなるでしょうか。その後node
null になり、ループから抜け出します。
では、再帰呼び出しに戻りましょうwalk(node, func)
。再帰呼び出しでは、関数自体を呼び出します。これは、関数の動作がこの反復の場合とまったく同じであることを意味します。この時点で、「でも、これは永遠に実行されるということではないのですか?」と思うかもしれません。しかし、そうはなりません!なんで?先ほどの停止条件を覚えていますか? ある時点で、子を持たないノードを渡します。これは、再帰呼び出しが終了して次の行に戻ることを意味します (node = node.nextSibling
)、実行は正常に進行します。DOM をツリー (ツリー) と考えると、これが意味することは、1 つのブランチを可能な限り下に移動し、最後に到達したら 1 レベル上に戻り、チェックして確認することです。他に兄弟がいる場合。ある場合は、その枝を可能な限り下ります。そうでない場合は、もう 1 レベル上に戻り、再度チェックを行います。このようにして、DOM ツリー全体をトラバースできます。