以下是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)
这是为了让递归安全地工作,我想.
例如,如果您只想使用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.
所以最初问题的答案是:你以这种方式定义递归函数,因为它是最灵活和最健壮的方式.