Reputation: 5075
Edit: I have to apologize, the problem I posted about actually does not exist in the code I posted, because I oversimplified it. I'll try to post something later.
Deletion would also be ok, but there are too many answers at present, so I cannot do it myself.
Edit2: Ok, here goes:
Let,
function F() {
this.field = "value" ;
var init = function(value) {
this.field = value ;
} ;
this.method = function() {
return this.field ;
} ;
init( arguments[0] ) ;
}
Now, instantiation of F
type,
var f = new F("newValue") ;
will set the value to the Window
object as this
points to it when called from the closure.
Binding this
to the Function
,
function F() {
var self = this ;
this.field = "value" ;
var init = function(value) {
self.field = value ;
} ;
this.method = function() {
return this.field ;
} ;
init( arguments[0] ) ;
}
will resolve the problem.
Still, what is the reason for this -- imho -- odd behaviour?
Upvotes: 2
Views: 402
Reputation: 5075
As it turns out, this is one of the dark corners of the ECMA specification for ECMAScript (hence JavaScript):
Finally a value is assigned for use with the this keyword. If the value assigned refers to an object then property accessors prefixed with the this keyword reference properties of that object. If the value assigned (internally) is null then the this keyword will refer to the global object.
(http://jibbering.com/faq/notes/closures/ ; thanks to @ Brian Flanagan for the link)
Apparently, during execution of a function that is assigned to a variable (within another Function
) the context is lost, the scope is thus set to null and this
will refer to the Window
Object
.
I'm not quite sure whether this is something to expect from a Function
initialized as a local variable. Typically I would expect a closure to have access to the scope it was created while that is still in memory, including it's predecessor in the scope chain.
This behaviour is different from a function that is the property of a Function
Object
, where the context is not lost and this
will correctly point to the owner of the member Function
(which is the Function
Object
or a member depending on how many layers there are).
The solution for this problem (while maintaining private Function
members, i.e. members that are only accessible from within the Function
's scope) is wrapping the function inside another Function
using Function.prototype.apply
(or Function.prototype.call
) to set the context manually:
function F() {
this.field = "value" ;
var self = this ;
var init = function(value) {
(function() {
this.field = value ;
}).apply(self,value) ;
} ;
this.method = function() {
return this.field ;
} ;
init( arguments[0] ) ;
}
This is similar to Function.prototype.bind
introduced in JavaScript 1.85 as well as the PrototypeJS library.
Edit: Forgot parentheses around the enclosed function in init
. This will result in a SyntaxError
.
Upvotes: 1
Reputation: 9148
Is this the example you were looking for ?
var F = function() {
var self = this ; //!! points correctly to the Function Object
this.field = "someValue" ;
var helper1 = function(){
return self.field;
}
var helper2 = function(){
return this.field;
}
this.method = function(){
return helper1();
}
this.method2 = function(){
return helper2();
}
}
var f = new F() ;
console.log(f.method()) ;
console.log(f.method2()) ;
In the case of method, it calls helper which uses self, which points to f when it gets created and hence it works.
In the case of method2, it uses helper2, which uses this. But the meaning of this while inside helper2 is the 'global' scope and hence returns undefined.
Upvotes: 1
Reputation: 2700
For the defining of method, you probably want to do something more like:
this.method = function()
{
return this.field;
}
Upvotes: 1
Reputation: 129529
This is (a reference to) the object on which a function was called.
So in your f.method()
call, this
is "f". NOT "F".
The fact that var self = this;
works is not due to this statement itself, but due to the fact that method2()
is a closure
To be more specific, the variable self
inside method2()
has a scope determined by F()
- in other words, "self" inside method2()
will ALWAYS refer o the value of self
which existed when "F" was defined (which, at the time, was of course "F" since at that point current object context was "F").
Upvotes: 2
Reputation: 413996
It's not correct to call this
an "operator". It's an object reference established by the runtime upon function activation.
Javascript is just a different language that does things in different ways. That this
is under control of the programmer is wonderfully powerful.
Also that code definitely does not work unless something else you didn't post is setting up a prototype object for "F". Neither "method" nor "method2" are callable from a reference to an instance of "F".
Upvotes: 1