55

Consider this piece of code

var crazy = function() {
    console.log(this);
    console.log(this.isCrazy); // wrong.
}
crazy.isCrazy = 'totally';
crazy();
// ouput =>
// DOMWindow
// undefined

From inside crazy() 'this' refers to the window, which I guess makes sense because normally you'd want this to refer to the object the function is attached to, but how can I get the function to refer to itself, and access a property set on itself?

Answer:

Don't use arguments.callee, just use a named function.

"Note: You should avoid using arguments.callee() and just give every function (expression) a name." via MDN article on arguments.callee

timoxley
  • 5,156
  • 3
  • 36
  • 40

11 Answers11

31

I think you are asking for arguments.callee, but it's deprecated now.

https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments/callee

var crazy = function() {
    console.log(this);
    console.log(arguments.callee.isCrazy); // right.
}
crazy.isCrazy = 'totally';
crazy();
// ouput =>
// DOMWindow
// totally
KZ.
  • 132
  • 2
  • 7
  • Thank you, this is exactly what I was looking for. How to refer to the function, from within that function, regardless of whether it is attached to an object or not, of if it has a name declared within the parent closure. Now i think about it, I already knew this, but never thought of it outside of removing anonymous event listener functions. – timoxley May 24 '11 at 11:30
  • If the second line of the function is not in fact wrong, do you mind removing the //wrong. from it? It makes the initial read confusing. – Patrick Sep 04 '12 at 17:37
  • 7
    Danger! Not a best practice! Will fail in 'use strict' mode. There are other ways of solving this issue out there. – Matt Jensen Jul 30 '13 at 21:11
  • You're right D: - `Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them` – i336_ May 10 '16 at 07:39
  • 2
    @MattJensen such as? – geoidesic Jan 27 '18 at 13:00
  • @geoidesic "Avoid using arguments.callee() by either giving function expressions a name or use a function declaration where a function must call itself." https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee – Matt Jensen Jan 27 '18 at 16:01
18

As rfw said, this is the most straight forward way to go if the function has one single name:

var crazy = function() {
    console.log(crazy);
    console.log(crazy.isCrazy);
};

crazy.isCrazy = 'totally';
crazy();

In case it may have different names, or you wanted to pass it around, it must be wrapped in a closure:

var crazy = (function(){
    var that = function() {
        console.log(that);
        console.log(that.isCrazy);
    };
    return that;
})();

crazy.isCrazy = 'totally';
crazy();
zupa
  • 12,809
  • 5
  • 40
  • 39
11

Bind the function to itself (taking a hint from answers by @ArunPJohny and @BudgieInWA):

crazy = crazy.bind(crazy);

This will give you access from the function to its properties via this.

> crazy()
function () {
    console.log(this);
    console.log(this.isCrazy); // works now
}

This seems like a better solution than the accepted answer, which uses the callee feature which is deprecated and doesn't work in strict mode.

You could also now have the function call itself recursively with this() were you so inclined.

We will call this self-thisifying. Write a little utility function:

function selfthisify(fn) { return fn.bind(fn); }
crazy = selfthisify(crazy);
crazy();

Or, if you prefer more "semantic" names, you could call it accessOwnProps.

If you're a syntactic sugar type of person, you could add a selfthisify property to the Function prototype:

Object.defineProperty(Function.prototype, 'selfthisify', {
    get: function() { return this.bind(this); }
});

Now you can say

crazy.selfthisify();
5

You have to give it its own name, so:

var crazy = function() {
    console.log(crazy);
    console.log(crazy.isCrazy);
}
crazy.isCrazy = 'totally';
crazy();

The variable this is only applicable in the scope of an object, for instance, if you invoked your version of the crazy function with crazy.call(crazy), it will call the function in the context of the function crazy and all would be well.

3

This has to deal with the scope of the function crazy. If can pass any scope to a function using the function call().

Instead of

crazy();

Use

crazy.call(crazy);

For details refer
http://odetocode.com/blogs/scott/archive/2007/07/05/function-apply-and-function-call-in-javascript.aspx
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Call
http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx

Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
2

You can use the call method

var crazy = function() {
    console.log(this);
    console.log(this.isCrazy);
}
crazy.isCrazy = 'totally';
crazy.call(crazy);
// calls crazy using crazy as the target, instead of window:
// functionToCall.call(objectToUseForThis);

Though if your function only ever has one name, you can do this:

var crazy = function() {
    console.log(crazy);
    console.log(crazy.isCrazy);
}
crazy.isCrazy = 'totally';
crazy();
BudgieInWA
  • 2,184
  • 1
  • 17
  • 31
  • 2
    Thanks, this also works. 'this' becomes attached to whatever object you call() the function on. Sweet. – timoxley May 24 '11 at 11:35
1

Easiest way to make the function itself available in its body is to do var crazy = function crazy2() { crazy2(); }, it's okay for crazy and crazy2 to have the same name since the first occurrence is the name in the outer scope and the second is the name in the function body.

Or simply do function crazy() { crazy(); } which will define crazy in both scopes.

Adam Bergmark
  • 7,316
  • 3
  • 20
  • 23
1

how can I get the function to refer to itself?

The idea of 'itself' does not exist with functions. What you need is an object and not just a function. An object has knowledge of itself available through the keyword 'this'. Within a function, 'this' points to the global object - in this case the window object. But if you use your function as a constructor function to create an object (using the new operator) then the object's 'this' pointer will point to the object itself.

i.e this points to the object if you write:

var anObject = new crazy();

So you can re-write your code as follows:

var crazy = function() {
    this.printMe = function(){
        console.log(this);
        console.log(this.isCrazy); 
    }
}

var anObject = new crazy(); //create an object
anObject.isCrazy = 'totally'; //add a new property to the object
anObject.printMe(); //now print

In case you wish to add the property before the object is created, then you have to add the property to the function's prototype as follows:

var crazy = function() {
    console.log(this);
    console.log(this.isCrazy); 
}

crazy.prototype.isCrazy = 'totally'; //add the property to the function's prototype
var anObject = new crazy(); //invoke the constructor

See more on my blog for a detailed explanation of these concepts with code-samples.

Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
rahulmohan
  • 1,285
  • 11
  • 19
  • 8
    StackOverflow exists to be a repository of high-quality questions and answers. When your short url service dies, or your blog article gets moved around, or your blogging service dies, this answer becomes even more useless. Please at the very least include copy-and-paste snippets of the portions of your article that directly address the question. SO doesn't exist to just be another boring link exchange site. Thanks! – sarnold May 23 '11 at 05:02
  • 2
    @sarnold: Thanks for pointing it out. I fully agree with you on this. Updated the answer accordingly. – rahulmohan May 23 '11 at 07:36
  • 4
    I find this answer quite misleading. First off, functions are first class objects in JS and as such there definitely __is__ an idea of itself for a function. Secondly, `this` does not refer to an object's self in JS but rather to the context in which a function is called. The very same function can have different `this` each time it is called depending on how it is called. – kralyk Aug 22 '14 at 19:39
0

In order to make you code to work follow below

        function crazy_object (crazy) {
          this.isCrazy = crazy
        }
        
        var create_crazy = new crazy_object('hello') //creating object
        
        console.log(create_crazy); //=> { isCrazy = 'hello' }
        
        var crazy = function() {
            console.log(this); //=> { isCrazy = 'totally' }
            console.log(this.isCrazy); //=> 'totally'
        }
        
        create_crazy.isCrazy = 'totally'; //=> isCrazy = 'totally'
        //below we pass the created object in function crazy.
        //And doing that we can use the keywork `this` and refer to the object
        crazy.call(create_crazy, null);

Using the call and apply method we can pass to a function a property,and in that function we can use the property with the keyword this

For example:

function speak (message) {
  console.log(`A person with name ${this.name} say ${message}`);
}

speak.call({ name: 'Roland' }, 'Javascript is awesome');

To use it with property:

function speak (message) {
  console.log(`A person with name ${this.name} say ${message}`);
}

var name = 'Roland'

speak.call({ name }, 'Javascript is awesome');
Roland
  • 24,554
  • 4
  • 99
  • 97
0

Are you actually trying to create an object 'class'?

function crazy(crazyState) {
   this.isCrazy = crazyState;
   console.log(this);
   console.log(this.isCrazy);
}
crazy.prototype.alertMe = function() { alert('I am '+ this.isCrazy +' crazy.'); }

var crazyObj = new crazy('totally');
crazyObj.alertMe();

crazyObj.isCrazy = 'not';
crazyObj.alertMe();
John Green
  • 13,241
  • 3
  • 29
  • 51
0

Funny that you should ask, mate. I just went through this same issue for a different purpose. The quick version of the final code is:

$a = function() {};

$ = function() {
    if (!(this instanceof $)) {
        return new $();
    }

    this.name = "levi";

    return this;
};

//helper function
var log = function(message) {
    document.write((message ? message : '') + "<br/>");
};

log("$().name == window.name: " + ($().name == window.name)); //false
log("$().name: " + $().name); //levi
log("window.name: " + window.name); //result

log();

log("$a instanceof $: " + ($a instanceof $)); //false
log("typeof $a: " + (typeof $a)); //function
log("typeof $: " + (typeof $)); //function

The critical piece:

    if (!(this instanceof $)) {
        return new $();
    }

If this isn't pointing to an object of the right type, then it makes a new one, which will properly scope this. The rest of the code is just there for verification that it does indeed work as intended.

Community
  • 1
  • 1
Levi Morrison
  • 19,116
  • 7
  • 65
  • 85