4

以下は、ダグラス・クロックフォードの「TheGoodParts」のコードです。

ほとんどの場合、コードは理にかなっています。を除いて、私はここでこの行を理解していません:

var walk_the_DOM = function walk(node, func) {

表示されているように、関数には2つの名前が付けられています-walk_the_dom()walk()

さらに下に行くと、コードが実際には両方の方法で呼び出されているので、実際にはこれらの名前の両方が関数を参照していることがわかります。

この関数に2つの名前が付けられているのはなぜですか?

// Define a walk_the_DOM function that visits every
// node of the tree in HTML source order, starting
// from some given node. It invokes a function,
// passing it each node in turn. walk_the_DOM calls
// itself to process each of the child nodes.

var walk_the_DOM = function walk(node, func) {
    func(node);
    node = node.firstChild;
    while (node) {

        // walk() called here

        walk(node, func);
        node = node.nextSibling;
    }
};

// Define a getElementsByAttribute function. It
// takes an attribute name string and an optional
// matching value. It calls walk_the_DOM, passing it a
// function that looks for an attribute name in the
// node. The matching nodes are accumulated in a
// results array.

var getElementsByAttribute = function (att, value) {
    var results = [];

   // walk_the_DOM() called here

    walk_the_DOM(document.body, function (node) { 
        var actual = node.nodeType === 1 && node.getAttribute(att);
        if (typeof actual === 'string' &&
                (actual === value || typeof value !== 'string')) {
            results.push(node);
        }
    });

    return results;
};
4

3 に答える 3

5

これは、再帰が安全に機能するためです。

たとえば、walk_the_DOM名前のみを使用したい場合、変数は後で再割り当てされたり、スコープが原因でアクセスできなくなったりする可能性があるため、関数自体の内部で使用するのは安全ではありません。

アップデート:

私はいくつかの調査を行いました、そしてこれが私が見つけたものです。まず、ECMAScript5仕様のセクション13を参照してください。関数を定義するには、a) FunctionDeclarationを使用する方法と、b)FunctionExpressionを使用する方法の2つがあります。

それらは非常に似ていますが、多少異なります。以下はFunctionDeclarationです:

function f() { };

これら2つは両方ともFunctionExpressionです:

var x = function() { };
var y = function f() { };

私たちにとって興味深い部分は、FunctionExpressionについてです。の場合var y = function f() { }、識別子fは関数本体の内側からのみ表示されます。つまり、の外のどこでも{ }typeof fを返しundefinedます。

次に、いくつかの実用的な例を示します。FunctionDeclarationを使用して再帰関数を記述したいとします。

function f1(x) { x > 5 ? console.log("finished") : f1(x + 1) };

次に、関数を別の変数に「コピー」して、別の変数に設定f1します。

var f2 = f1;
var f1 = function() { console.log("Kitteh") };

しかし、これは期待どおりに機能しません。

f2(1); // outputs: Kitteh

ここで、ダグラス・クロックフォードの再帰関数を定義する方法を使用した場合:

var f1 = function myself(x) { x > 5 ? console.log("finished") : myself(x + 1) };

このようにして、関数を任意の変数に何度でも再割り当てできます。同時に、変数に割り当てられた関数ではなく、関数が常に自分自身を呼び出すようにしましたf1

したがって、最初の質問に対する答えは、再帰関数をこの方法で定義することです。これは、最も柔軟で堅牢な方法だからです。

于 2012-09-10T18:42:47.140 に答える
1

関数は再帰的であるためwalk、無名関数スコープの内側と外側の両方で呼び出す必要があります。

var test = function test_recursive( num ) {
    if( num < 10 ) {
        test_recursive( --num );
    }
}

var num = test( 5 );
于 2012-09-10T18:46:13.353 に答える
1

walk_the_DOMこれは、関数を外部から呼び出す方法です。

ただし、関数が再帰を使用したり、バイトを節約したり、書き込みを高速化したりする場合は、関数を呼び出しますwalk

編集:シェダルが指摘したように、変数walk_the_DOMは後で再割り当てされる可能性があります。そのため、この関数は機能しなくなります。

于 2012-09-10T18:46:24.063 に答える