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

时间:2013-08-22 16:02:41

标签: javascript jquery function scope closures

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

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

mdn warning

所以我决定不使用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未定义?

jsfiddle DEMO

3 个答案:

答案 0 :(得分:2)

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

[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)

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

答案 1 :(得分:1)

函数表达式的名称不会在它定义的命名空间中引用自身(IE中的错误),但它本身就引用了它自己

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

如果您想要引用函数以便可以重复使用它,请创建对它的引用,或者返回编写函数声明 > function as a statement),或将函数表达式设置为变量,并根据需要传递变量

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

请注意,在此示例中名为foo函数中,foobar都将指向相同的函数 ,除非稍后再次更改bar

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

答案 2 :(得分: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);
});