Reputation: 2821
I really can't explain myself why I failed in creating a closure and I get undefined
in the code below:
function A() {
this.p1=1;
this.p2=2;
this.f1=function(){
alert(this.p1);
}
this.f2=function(){
alert(this.p2);
}
this.action=function(param){
if (param=='1')
return this.f1;//by case
else if (param=='2')
return this.f2;
};
}
var v=new A();
v.action("1")();
Upvotes: 1
Views: 97
Reputation: 1082
As you intended
v.action("1")
returns the function defined as
function(){
alert(this.p1);
}
You can also call it by adding a pair of brackets, like you did. However the this
in that function will be bound to the global object (in browser it is window
). And window.p1
is undefined
. That's what you get as output.
As mentioned already, you can decide what should be this
in the function by calling it using call
instead of the brackets:
v.action("1").call(v);
What this
means in JavaScript is quite confusing. An explanation that helped me understand can be found in section 3.3 The meaning of this (the egregious disaster) of Javascript in Ten Minutes (a worthwhile read though the whole document takes a lot more than ten minutes).
Upvotes: 0
Reputation: 76395
Looks to me like you're not 100% sure on what a closure is... Starting with your code:
function A()
{
this.p1=1;//public
var p2=2;//private
this.f1=function()
{
alert(this.p1);
};
this.f2=function()
{
alert(p2);
};
Here, I've defined p2
as a variable, local to the constructor's scope, yet the public method f2
can sitl access its value, change it even. That's a closure: code/data contained within its own specific scope. What you're doing with the following code:
this.action=function(param)
{
if (param=='1')
{
return this.f1;
}
return this.f2;
};
}
var v=new A();
v.action("1")();
Has little or nothing to do with a closure, you're returning a reference to a function (that happens to be an object method in this specific case). Why, then doesn't this point
to the object it came from? Simple:
var foo = {name:'someObject'};
foo.retVal = v.action('1');//returns function
//much later:
foo.retVal();
Would you expect this
to point to v
, still? And wouldn't that be hellish to debug? upon calling a function (method or not), this
will be the pointer of the context-object in which the function is called. Once v.action('1')
returns, in your example, the function is returned to the global object, hence this will point to this
or window
Upvotes: 1
Reputation: 21090
The functions are not binded to a specific this, that is to say:
(function() { console.log(this) })(); // Window
You can either use the call method, or (better) use the .bind method (make sure to polyfill for older browsers):
function A() {
this.p1 = 1;
this.p2 = 2;
}
A.prototype.f1 = function() {alert(this.p1)};
A.prototype.f2 = function() {alert(this.p2)};
A.prototype.action = function(param) {
if ('1' == param) {
return this.f1.bind(this);
} else if (param == '2') {
return this.f2.bind(this);
}
};
var v = new A();
v.action("1")(); // 1
The bind method returns a new function which calls the original function with this set to the bind's argument. Function.prototype.bind documentation on MDN
v.action("1")
is roughly the same as action.call(v, "1")
Upvotes: 1
Reputation: 9051
Inside your nested function this
has another meaning.
Try using variable to pass reference inside, see jsfiddle.
Upvotes: 0
Reputation: 672
Inside of a closure like this, "this" actually refers to the Window when it is called later. In order to avoid this, you need to assign "this" to another variable, like "that":
function A() {
var that = this;
that.p1=1;
that.p2=2;
that.f1=function(){
alert(that.p1);
}
that.f2=function(){
alert(that.p2);
}
that.action=function(param){
if (param=='1')
return that.f1;//by case
else if (param=='2')
return that.f2;
};
}
var v=new A();
v.action("1")();
Upvotes: 0
Reputation: 700342
That has nothing to do with a closure.
You are returning a function reference from the method, and when you call it you expect it to be executed as a method in the object, but it's executed as a function with the global scope as context.
Use the call
method to call the function in the context of the object:
v.action("1").call(v);
Upvotes: 4