1

js在参数中命名函数,无法访问函数外

因为 ECMAScript 第 5 版禁止在严格模式下使用 arguments.callee()。

mdn警告

所以我决定不使用callee,而是使用命名函数

mdn中的例子

function factorial (n) {
    return !(n > 1) ? 1 : factorial(n - 1) * n;
}
[1,2,3,4,5].map(factorial);

变得:

[1,2,3,4,5].map(function factorial(n) {
    return !(n > 1) ? 1 : /* what goes here? */ factorial(n - 1) * n;
});

这是个好主意,但我想重用该功能factorial

演示

function d(x){return x;}

d(function a(){});
d(a);// this is not work, a is undefined(works in ie, failed in ff and chrome)

这让我很困扰,据我所知,js 中的范围是函数级的,为什么第二个 a 是 undefined ?

jsfiddle 演示

4

3 回答 3

2

你真的在这里问了两个问题。第一个很简单:

[1,2,3,4,5].map(function factorial(n) {
    return !(n > 1) ? 1 : /* what goes here? */ factorial(n - 1) * n;
});

你所拥有的一切都很好。换句话说,由于您正在命名您的函数(阶乘),因此该标识符在函数体内可用,从而启用递归。

你的第二个问题有点棘手:

function d(x){return x;}

d(function a(){});
d(a);// this is not work, a is undefined(works in ie, failed in ff and chrome)

a未定义是正确的。如果您阅读ECMAScript 规范,第 13.2.1 节明确指出创建的新执行上下文包括实际参数(参数列表)。也就是说,a是在 的执行上下文中定义的d,而不是调用者。看起来 IE 正在表达错误的行为。

于 2013-08-22T16:35:55.640 回答
1

函数表达式的名称不会在其定义的命名空间中引用自身(IE 对此有错误),但会在自身内部引用自身

[1].map(function foo() {return foo;});
// [function foo() {return foo;}]
foo;
// undefined

如果你想要一个对函数的引用以便它可以被重用,创建一个对它的引用,或者回到编写函数声明函数作为语句),或者将函数表达式设置为变量,然后传递变量如预期的

var bar = function foo() {return foo;};
[1].map(bar);
// [function foo() {return foo;}]
foo;
// undefined
bar;
// function foo() {return foo;}

请注意,在此示例中命名的函数内部,两者和都将指向同一个function,除非稍后再次更改。foofoobarbar

var bar = function foo() {return foo === bar;};
bar(); // true, bar is foo inside the function
// change value of bar, keep a reference to function foo
var temp = bar;
bar = 'something else';
temp(); // false, bar is no longer foo inside the function
于 2013-08-22T16:10:17.687 回答
0

你说你之前的例子行不通,但我不得不不同意你的观点,

[1,2,3,4,5].map(function factorial(n) {
    return n == 0 ? 1 : factorial(n - 1) * n;
});

我尝试使用基本日志记录(是的,我对其进行了一些修改),并且每次递归都记录了 n-1,表明递归工作正常。我相信保罗解释得很好。

无论如何,我建议改变你在这里的思维方式,因为想象一下你是否找到阶乘(100)。你会做

... * factorial(98 - 1) * 98 * 99 * 100

想象一下超载。我建议添加一个可选参数,它是当前评估的阶乘之和,您的结果是相同的,但重载要少得多。

[1,2,3,4,5].map(function factorial(n, sum) {
    var sum = sum || 1;
    return n == 0 ? 1 : factorial(n - 1, sum*n);
});
于 2013-08-22T16:42:37.810 回答