Reputation: 10436
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
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
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