Can a JavaScript function return itself?
Asked Answered
V

6

30

Can I write a function that returns iteself?

I was reading some description on closures - see Example 6 - where a function was returning a function, so you could call func()(); as valid JavaScript.

So I was wondering could a function return itself in such a way that you could chain it to itself indefinitely like this:

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

Using arguments object, callee or caller?

Valentinevalentino answered 5/8, 2011 at 16:21 Comment(2)
Related question: Javascript FAB framework on Node.jsLicentious
#6085372 #1792293Crocodile
D
36

There are 2-3 ways. One is, as you say, is to use arguments.callee. It might be the only way if you're dealing with an anonymous function that's not stored assigned to a variable somewhere (that you know of):

(function() {
    return arguments.callee;
})()()()().... ;

The 2nd is to use the function's name

function namedFunc() {
    return namedFunc;
}
namedFunc()()()().... ;

And the last one is to use an anonymous function assigned to a variable, but you have to know the variable, so in that case I see no reason, why you can't just give the function a name, and use the method above

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

They're all functionally identical, but callee is the simplest.

Edit: And I agree with SLaks; I can't recommend it either

Deutsch answered 5/8, 2011 at 16:36 Comment(4)
Worth noting that arguments.callee throws an error in ES5 Strict ejohn.org/blog/ecmascript-5-strict-mode-json-and-moreLublin
@abbotto Method 3 works fine for me, but yes method 2 is the "right" way to do it. As for deprecation, note that this answer is 5 years oldDeutsch
@Flambino, you are correct. Method 1: Should generally be avoided altogether because arguments.callee has been deprecated. See: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Method 2: This is the best way to do a recursive function call in JS, because the function isn't anonymous and it's name will show up in stack traces.Communion
@Deutsch @MarkFox @Communion can combine methods 1 and 2 to eliminate callee usage (function X() {return X;})()()()().... ; thereby aleviating deprecation issue. The function name also appears in stack traces. It's concise, compliant and does not pollute the namespace.Dispensable
A
13

Yes.
Just return arguments.callee;


However, this is likely to result in very confusing code; I do not recommend it.

Ampoule answered 5/8, 2011 at 16:22 Comment(4)
I would just name the function, instead using arguments.callee for two reasons: 1. Functions are generally optimized by implementations, if you don't use the arguments object, it won't be generally created (the execution context will be initialized faster) -of course, if the function uses eval, it usually can't be optimized-. 2. The arguments object had changes on ES5 strict mode, and the arguments.callee property has been disallowed (again also for optimization and security concerns), so basically to write future-proof code, I would recommend to just name the function. :)Licentious
@CMS: Are you sure that callee is no longer allowed? I thought that was caller.Ampoule
both are disallowed, and caller AFAIR was actually never part of the spec, but it was supported by many implementations, that's why on ES5, for strict functions, both caller and callee are assigned to a thrower function, see the Step 14 in 10.6 Arguments ObjectLicentious
Also, check this simple benchmark test to see how the arguments object creation affects performance. BTW, the caller property was really dangerous, it allowed to "break" closures in some implementations, for example in Spidermonkey some techniques like this one allow to leak privately scoped functions.Licentious
C
8

You can do what you want as following:

// Do definition and execution at the same time.
var someFunction = (function someFunction() {

    // do stuff
    return someFunction
 })();

 console.log(someFunction)

arguments.callee is not supported in JavaScript strict mode.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode

Courser answered 31/10, 2015 at 3:16 Comment(0)
H
5

Even sorter that all the above is:

f=()=>f
Hostetler answered 8/8, 2018 at 13:11 Comment(2)
How will you add any logic to the function?Gaff
Defining anything to a variable without const/let/var is a bad practice, and also it will not work in strict mode. @Sam you can add the logic to this arrow function using {} f.e. const f = () => { console.log('test'); return f }Anaplastic
A
1

There is a simple way to achieve this doing the following:

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
Alfonzoalford answered 17/8, 2017 at 1:58 Comment(4)
reason for -1, this is not what was asked in the original postEssonite
@Essonite OP asked for a function that returns itself. The above function returns itself. Am I missing something?Gaff
@SamuelEbert, yes this function returns itself, but also is bloated with functional which is useless for the context of the question and focuses on that additional functional. It's like I'd ask an example of usage the verb "to be" and I'd get as response "Hamlet" by Shakespeare without even pointing where is the example of the verb "to be" is in the text.Essonite
@micnic, Thank you for clarifying. I actually agree with you. :)Gaff
A
0

It is also possible just to return the argument the self invokable function like

console.log( (function(a) {  return a; })(1) ); // returns 1
Arithmomancy answered 24/8, 2017 at 22:37 Comment(1)
why? he asked somthing that return function (itself) and i gave one. was that confuse?Hyperostosis

© 2022 - 2024 — McMap. All rights reserved.