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?

Cipi
  • 11,055
  • 9
  • 47
  • 60
fbas
  • 1,676
  • 3
  • 16
  • 26
  • Related question: [Javascript FAB framework on Node.js](http://stackoverflow.com/questions/3799238) – Christian C. Salvadó Aug 05 '11 at 16:25
  • http://stackoverflow.com/questions/6084872/an-object-that-returns-an-instance-of-itself http://stackoverflow.com/questions/1791793/javascript-function-call-to-itself –  Aug 05 '11 at 16:26

6 Answers6

35

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

Flambino
  • 18,507
  • 2
  • 39
  • 58
  • 11
    Worth noting that `arguments.callee` throws an error in ES5 Strict http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/ – Mark Fox Mar 10 '13 at 21:10
  • 1
    @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 old – Flambino Dec 19 '16 at 16:01
  • 2
    @Flambino, you are correct. Method 1: Should generally be avoided altogether because arguments.callee has been deprecated. See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee 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. – abbotto Dec 19 '16 at 16:04
  • @Flambino @MarkFox @abbotto 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. – Moika Turns Apr 19 '18 at 09:40
13

Yes.
Just return arguments.callee;


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

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 8
    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. :) – Christian C. Salvadó Aug 05 '11 at 16:55
  • @CMS: Are you sure that `callee` is no longer allowed? I thought that was `caller`. – SLaks Aug 05 '11 at 17:22
  • 5
    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](http://es5.github.com/#x13.2.3), see the *Step 14* in [10.6 Arguments Object](http://es5.github.com/#x10.6) – Christian C. Salvadó Aug 05 '11 at 17:47
  • 2
    Also, check this simple [benchmark test](http://jsperf.com/arguments-callee-vs-fn-name) 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](http://jsfiddle.net/cmsalvado/87C7c/) allow to *leak* privately scoped functions. – Christian C. Salvadó Aug 05 '11 at 18:29
7

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

RubenLaguna
  • 21,435
  • 13
  • 113
  • 151
ataru
  • 401
  • 3
  • 6
3

Even sorter that all the above is:

f=()=>f
מתן ל
  • 214
  • 1
  • 9
  • 2
    How will you add any logic to the function? – Danny Apr 14 '21 at 16:28
  • 2
    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 }` – Jakub Jan 02 '22 at 15:23
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
zero_cool
  • 3,960
  • 5
  • 39
  • 54
  • 3
    reason for -1, this is not what was asked in the original post – micnic Jun 05 '18 at 12:50
  • @micnic OP asked for a function that returns itself. The above function returns itself. Am I missing something? – Danny Apr 14 '21 at 16:30
  • 1
    @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. – micnic Apr 15 '21 at 07:51
  • @micnic, Thank you for clarifying. I actually agree with you. :) – Danny Apr 15 '21 at 15:20
0

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

console.log( (function(a) {  return a; })(1) ); // returns 1
konstantin555
  • 102
  • 2
  • 7