JavaScript函数能够返回自己吗?

30

我能写一个返回自己的函数吗?

我阅读了关于闭包的一些描述-请看例子6-其中一个函数返回了一个函数,这样你可以调用func()();作为有效的JavaScript。

所以我在想是否可以编写一个函数以这种方式返回它本身,从而可以无限地将其链接到自身,如下:

func(arg)(other_arg)()(blah);

使用arguments对象、callee还是caller


相关问题:在Node.js上使用Javascript FAB框架 - Christian C. Salvadó
https://dev59.com/xm025IYBdhLWcg3wT0Lqhttps://dev59.com/-0rSa4cB1Zd3GeqPW3wG - user871499
6个回答

35

有2-3种方法。其中一种就是,如你所说,使用arguments.callee。如果你正在处理一个未被存储为变量的匿名函数(至少你不知道它在哪里被分配),这可能是唯一的方法:

(function() {
    return arguments.callee;
})()()()().... ;
第二种方法是使用函数的名称。
function namedFunc() {
    return namedFunc;
}
namedFunc()()()().... ;

最后一种方法是使用分配给变量的匿名函数,但您必须知道该变量,因此在这种情况下,我看不出为什么您不能给函数一个名称,并使用上述方法。

var storedFunc = function() {
    return storedFunc;
};
storedFunc()()()().... ;

它们在功能上都是相同的,但是callee是最简单的。

编辑:我也同意SLaks的观点,我也不建议使用它。


11
值得注意的是,在 ES5 严格模式下,arguments.callee 会抛出一个错误。http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/ - Mark Fox
1
@abbotto,方法3对我来说很好用,但是确实方法2是“正确”的做法。至于弃用问题,请注意这个答案已经有5年的历史了。 - Flambino
2
@Flambino,你是正确的。方法1:通常应该完全避免使用,因为arguments.callee已被弃用。请参见:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee方法2:这是在JS中进行递归函数调用的最佳方式,因为该函数不是匿名的,并且其名称将显示在堆栈跟踪中。 - abbotto
@Flambino @MarkFox @abbotto可以结合方法1和2,使用(function X() {return X;})()()()().... ;来消除被调用者的使用,从而减轻弃用问题。函数名也会在堆栈跟踪中出现。它简洁、符合规范,不会污染命名空间。 - Moika Turns

13

是的。
只需返回 arguments.callee;


但是,这可能会导致非常混乱的代码;我不建议使用。


8
为两个原因,我建议仅使用函数名称而不是arguments.callee:1. 实现通常会对函数进行优化,如果不使用arguments对象,则通常不会创建它(执行上下文将更快地初始化)-当然,如果函数使用eval,则通常无法进行优化-。2. ES5严格模式中arguments对象有所改变,并且arguments.callee属性已被禁用(同样出于优化和安全考虑),因此基本上为编写具有未来性的代码,我建议只使用函数名称。 :) - Christian C. Salvadó
@CMS:你确定 callee 不再被允许使用了吗?我记得应该是 caller - SLaks
5
两者都不允许,并且据我所记,caller实际上从未成为规范的一部分,但是它被许多实现支持,这就是为什么在ES5中,对于严格模式下的函数,callercallee都被赋值为一个thrower function,请参见10.6 Arguments Object中的Step 14 - Christian C. Salvadó
2
另外,检查一下这个简单的基准测试,看看arguments对象的创建如何影响性能。顺便说一句,caller属性真的很危险,它允许在某些实现中“破坏”闭包,例如在Spidermonkey中,一些技巧(比如这个)可以泄漏私有作用域函数。 - Christian C. Salvadó

7

4
甚至比以上所有内容都更短的是:

f=()=>f


2
你将如何向函数添加任何逻辑? - Sam
2
在不使用const/let/var的情况下将任何内容定义为变量是一种不好的做法,而且在严格模式下也无法工作。@Sam,您可以使用{}来添加此箭头函数的逻辑,例如: const f = () => { console.log('test'); return f } - Jakub

1
有一个简单的方法可以实现这一点,只需按照以下步骤操作:
let intArr = [];
function mul(x){
    if(!x){
        return intArr.reduce((prev, curr) => prev * curr)
    }
    intArr.push(x);
    return mul;
}

console.log(mul(2)(4)(2)()); => outputs 16

3
-1的原因是,这不是原始帖子中所问的内容。 - micnic
@micnic OP要求一个返回自身的函数。上面的函数返回自身。我有什么遗漏吗? - Sam
1
@SamuelEbert,是的,这个函数确实返回了自身,但它还带有在问题的上下文中无用的功能,并且专注于那些额外的功能。这就像我要求一个使用动词“to be”的例子,而我得到的回答是莎士比亚的《哈姆雷特》,甚至没有指出文本中动词“to be”的例子在哪里一样。 - micnic
@micnic,谢谢你的澄清。我实际上同意你的观点。 :) - Sam

0

还有一种可能,就是像自调用函数那样直接返回参数。

console.log( (function(a) {  return a; })(1) ); // returns 1

1
为什么?他问了一个返回函数(本身)的东西,我给了一个。那很困惑吗? - מתן ל

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接