views:

121

answers:

5

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?

+1  A: 

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".

Pointy
The MDC lists `this` under operators. Also, you don't really offer an explanation.
FK82
Apparently the MDC and I differ on the definition of "operator" :-)
Pointy
It's indeed listed under "Operators" in the MDC reference, but the standard just calls it a "keyword", which I think is much more accurate.
Pointy
@FK82 The `this` keyword is not an operator. It does not operate upon operands. It is just a keyword that references an object. The MDC should hire someone to proofread their stuff.
Šime Vidas
@ Šime Vidas, Pointy: I was just sticking to canonic definitions here. Personally, I call `this` a "keyword" as well.
FK82
+2  A: 

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").

DVK
+1  A: 

For the defining of method, you probably want to do something more like:

this.method = function()
{
    return this.field;
}
jelbourn
+1  A: 

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.

letronje
Correct, oversight on my part. I corrected it.
FK82
+1  A: 

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.

FK82