递归| 两个函数名称

4 javascript

以下是Douglas Crockford的The Good Parts的代码.

在大多数情况下,代码是有道理的.除此之外,我不明白这一行:

var walk_the_DOM = function walk(node, func) {
Run Code Online (Sandbox Code Playgroud)

因为看起来这个函数有两个名字 - walk_the_dom()walk()

再往下看,你可以看到代码实际上是双向调用的,所以这两个名字实际上都引用了这个函数.

为什么这个函数有两个名字?

// 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;
};
Run Code Online (Sandbox Code Playgroud)

Dmy*_*nko 5

这是为了让递归安全地工作,我想.

例如,如果您只想使用walk_the_DOM名称,则可以稍后重新分配变量,或者由于范围而无法访问该变量,因此在函数本身内部使用它是不安全的.

更新:

我做了一些研究,这就是我发现的.首先,请参阅ECMAScript 5规范,第13节.定义函数有两种方法:a)使用FunctionDeclaration,b)使用FunctionExpression.

它们看起来非常相似,但也有些不同.以下是FunctionDeclaration:

function f() { };
Run Code Online (Sandbox Code Playgroud)

这两个都是FunctionExpression:

var x = function() { };
var y = function f() { };
Run Code Online (Sandbox Code Playgroud)

对我们来说有趣的部分是关于FunctionExpression.在的情况下var y = function f() { },标识符f唯一从函数体内可见的.换句话说,在任何地方之外{ },typeof f都会回归undefined.

现在是一些实际例子的时候了.假设我们想使用FunctionDeclaration编写递归函数:

function f1(x) { x > 5 ? console.log("finished") : f1(x + 1) };
Run Code Online (Sandbox Code Playgroud)

现在我们要将函数"复制"到另一个变量并设置f1为其他变量:

var f2 = f1;
var f1 = function() { console.log("Kitteh") };
Run Code Online (Sandbox Code Playgroud)

但这不能按预期工作:

f2(1); // outputs: Kitteh
Run Code Online (Sandbox Code Playgroud)

现在,如果您使用Douglas Crockford定义递归函数的方式:

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

这样,您可以根据需要将函数重新分配给任何变量.同时,我们确保函数始终调用自身,而不是分配给变量的某些函数f1.

所以最初问题的答案是:你以这种方式定义递归函数,因为它是最灵活和最健壮的方式.