Earth Engine
Earth Engine

Reputation: 10436

Why the property of this cannot be accessed directlly within a private function in a closure?

In my own answer for A JavaScript VM that interprets code written in JSON I stated that the "public" properties of a JavaScript closure cannot be accessed in a "private" function.

The example given in that post is

function anobject(){
    var privatefunction = function(){
        //publicfunction(); //wrong; you have no access to it
        console.log(this); //refer to the global object, not the object creating
    };
    this.publicfunction = function(){
        console.log(this); //refer to the object creating
    }
}

I think the reason is for some backward compatibility issues privatefunction must belong to the global object. So the public function is only an anonymous function that assigned to a property of this. This explains why calling publicfunction will fail because it need to have a reference to this first.

However, the following fix is still not work:

function anobject(){
    var privatefunction = function(){
        //publicfunction(); //wrong; you have no access to it
        console.log(this); //refer to the object creating
    }.bind(this);
    this.publicfunction = function(){
        console.log(this); //refer to the object creating
    }
}

As I explicitly specify that privatefunction should be bound with the object creating, calling publicfunction should work but it does not. I have to do the following:

function anobject(){
    var privatefunction = function(){
        this.publicfunction();
        console.log(this); //refer to the object creating
    }.bind(this);
    this.publicfunction = function(){
        console.log(this); //refer to the object creating
    }
}

Another workaround (the way that I am using) is the following:

function anobject(){
    var privatefunction = function(){
        publicfunction();
        console.log(this); //refer to the object creating
    };
    var publicfunction = function(){
        console.log(this); //refer to the object creating
    }
    this.publicfunction = publicfunction;
}

Now is the question part. What is the reason behind this behavior? What is it trying to avoid by disabling access this's properties without explicit specification?

UPDATE: the main part of the question is : When the interpreter cannot find a name in the scope chains, why should'nt it have a look at the this properties?

Upvotes: 3

Views: 101

Answers (2)

Will
Will

Reputation: 41

In the second example, publicfunction() is delcared as a property of the object this:

this.publicfunction = function(){
    console.log(this);
}

Therefore, this function is not directly accessible by its name publicfunction(), and that is independent of the context. The function does not actually belong to any context, but rather to the object of which it is a property.

In your example, when privatefunction() calls publicfunction(), this raises an error because there is no function declared as a variable with the name publicfunction(), and not because this's properties are not accessible:

function anobject(){
    var privatefunction = function(){
        //publicfunction(); // You cannot call publicfunction() because there is
                            // no function defined with this name
    }.bind(this);
    this.publicfunction = function(){
        console.log(this);
    }
}

Look at this example, publicfunction() is not accessible even within anobject():

function anobject(){
    this.publicfunction = function() {
        console.log(this);
    }
    // publicfunction(); // Wrong because publicfunction()
                         // was not defined as a variable
}

However, if publicfunction() was defined as a variable within the context of anobject(), then this function would be accessible by its name. For example you can simply declare function publicfunction() within the closure of anobject():

function anobject(){
    function publicfunction() {
        console.log(this);
    }
    publicfunction(); // You can access publicfunction() here
}

But in this case, publicfunction() is not accessible outside the execution context of anobject(), therefore it can be regarded as a 'private' function:

var a = new anobject();
if(typeof a.publicfunction === 'undefined')
    console.log('Public function is undefined outside of anobject()');

As a result, that's why we use the this keyword to declare publicfunction(): it makes it accessible outside the context of anobject(), but doing so define this function only as a property of anobject().

Therefore the only way to access this function is by calling this.publicfunction():

function anobject(){
    var privatefunction = function(){
        this.publicfunction();
        console.log(this);
    }.bind(this);
    this.publicfunction = function(){
        console.log(this);
   }
}

More details regarding the this keyword: How does "this" keyword work within a function?

Variable vs. Properties in JavaScript: http://javascriptweblog.wordpress.com/2010/08/09/variables-vs-properties-in-javascript/

Upvotes: 1

Matteo Tassinari
Matteo Tassinari

Reputation: 18584

The problem here is that the reference this is determined by the caller of the function/method, for example:

function anobject(){
    // here "this" is the object
    var privatefunction = function(){
        // here "this" is the object **that called privatefunction()**
    };
    this.publicfunction = function(){
        // this method will always be called by the object, so "this" is the object
    }
}

To achieve what you want you could also try this:

function anobject(){
    var that = this;
    var privatefunction = function(){
        [do what you like using "that"]
    };
    this.publicfunction = function(){
        [here you can use "this" directly, or "that"]
    }
}

See also how javascript scope works, here What is the scope of variables in JavaScript? and on the web.

Upvotes: 4

Related Questions